Non-Sealed Subtypes in Java
A `non-sealed` class or interface is a permitted subtype of a sealed type that reopens inheritance. Once a subtype is declared `non-sealed`, other classes can extend or implement it without being listed in the original sealed type's `permits` clause.
A sealed class or interface restricts which types may directly extend or implement it. Every direct permitted subtype must be declared as `final`, `sealed`, or `non-sealed` so the compiler knows how inheritance continues.
Declaring a permitted subtype as `non-sealed` removes that restriction at the next level. For example, if `Shape` permits `Circle` and `FlexibleShape`, and `FlexibleShape` is `non-sealed`, another class can extend `FlexibleShape` without being named by `Shape`.
`non-sealed` does not mean that the type itself can be extended by absolutely anything regardless of normal Java access rules. The extending type must still satisfy ordinary inheritance requirements, such as accessibility and class/interface compatibility.
This feature is useful when a design wants a controlled top-level hierarchy but intentionally allows an open branch underneath one permitted subtype. It is particularly relevant when deciding how exhaustive pattern matching or other hierarchy-based logic should be structured.
Key points
- `non-sealed` reopens inheritance below a sealed type.
- A direct permitted subtype of a sealed type must be `final`, `sealed`, or `non-sealed`.
- Classes can extend a `non-sealed` permitted class without being listed in the original `permits` clause.
- `non-sealed` affects inheritance restrictions; normal Java access and inheritance rules still apply.
Interview questions
Why would you declare a permitted subtype as `non-sealed`?
You use `non-sealed` when the parent hierarchy should remain restricted but one particular branch should allow further extension. The subtype remains a permitted direct child of the sealed parent. Classes can then extend that subtype without being named by the parent. This gives the hierarchy a controlled boundary with an intentionally open branch.
What must a direct subclass of a sealed class declare?
A direct subclass of a sealed class must declare itself `final`, `sealed`, or `non-sealed`. These choices determine whether inheritance ends, remains restricted, or becomes open. The compiler uses this declaration to enforce the hierarchy's rules. A direct subclass also needs to be permitted by the sealed parent, either explicitly or according to the applicable permits rules.
Can a class extend a `non-sealed` subtype without appearing in the original `permits` clause?
Yes. Once a permitted subtype is declared `non-sealed`, its own subclasses are not required to be listed in the original sealed parent's permits declaration. They still have to satisfy normal Java inheritance and accessibility rules. This is the main distinction between an opened branch and a sealed branch.
How does `non-sealed` affect a sealed hierarchy?
It creates an intentional escape from the parent's closed inheritance boundary at a specific permitted subtype. The sealed parent still controls which types can be its direct children, but it no longer controls descendants below the `non-sealed` branch. Consequently, reasoning about all possible descendants of the parent requires treating that branch as open. This can matter when designing exhaustive type handling and maintaining invariants across the hierarchy.