In "F-Bounded Polymorphism: Type-Safe Builders in Java", author "fbounded" addresses what he calls a fundamental inheritance problem in Java's fluent builder pattern.
When a base builder class returns this, subclass methods lose type information - calling a parent method on CarBuilder returns VehicleBuilder, breaking the method chain, because this loses the reference type of being a CarBuilder, being a VehicleBuilder instead.
The fix uses a self-referential type bound: VehicleBuilder<B extends VehicleBuilder<B>> declares that B must be a subtype of VehicleBuilder parameterized by itself. Concrete builders then extend VehicleBuilder<CarBuilder>, allowing base class methods to return the actual subclass type without casts.
This pattern appears throughout the Java standard library. Enum<E extends Enum<E>> uses the same technique to ensure Planet.compareTo() only accepts another Planet, not any Enum, turning potential runtime errors into compile-time guarantees. The Comparable interface follows similar logic.
The approach scales cleanly to multiple subclasses - each declares itself as its own type parameter - but struggles with deeper inheritance hierarchies where a subclass of CarBuilder cannot re-specialize the already-bound B parameter.
In practice, one level of builder inheritance handles most real-world cases, making F-bounds a practical solution rather than theoretical curiosity. The unchecked cast to B remains necessary in the base class implementation but is hidden from client code, preserving type safety at call sites.
Interesting article.