Java sealed classes, introduced in Java 17, let developers list exactly which subtypes may implement or extend a type. Paired with pattern matching for switch, they let the compiler check that a switch covers every permitted subtype, which removes the need for a default clause in many cases.
Neil Madden walked through the feature in a post on his blog on April 24, 2026. His toy example used a sealed interface with two record implementations, TypeA and TypeB. A switch expression over that interface compiled without a default because the compiler knew both cases were covered, and leaving one out would have produced a compile-time error.
The same check creates a new kind of breaking change. In Madden’s example, adding a TypeC subtype makes the consumer code fail to compile because of the missing case. “So if you export a sealed type in your API then adding a new subtype is a breaking change that would require a major version bump (if you’re following SemVer),” he wrote.
Runtime Behavior When Hierarchies Change
Things change when the sealed type and its clients are compiled separately. When Madden recompiled only the sealed interface and then triggered the new case, the old consumer code threw a MatchException at runtime. OpenJDK’s guide “Preparing for Change: Safe Switching over Sealed APIs,” by Angelos Bimpoudis, Alex Buckley and Brian Goetz and dated August 11, 2026, describes the same behavior: an exhaustive switch covers the subtypes the compiler knew about, not ones added later.
The authors see that as useful feedback. “A default label is almost never the right answer,” they wrote, because a catch-all hides the developer’s intent and can let a program carry on with an erroneous result. Where practical, they recommend handling each permitted subtype with its own case. When that isn’t practical, developers should use the narrowest type pattern that still makes the switch exhaustive, such as case Fruit other rather than case Object other. The guide also asks API authors to document how they expect their sealed types to evolve.
Madden’s conclusion is that sealed types are most useful inside a single component, where everything gets recompiled together and the compiler’s guarantees hold. Exposed in a public library API, “you may just be introducing new ways to break code, often only detectable at runtime.” He said he ran into these subtleties while reviewing Java’s preview support for PEM-encoded cryptographic objects, which bakes a sealed interface into a public API and tells clients to pattern match against it.