Master Core Java Programming From Scratch

Clear, interactive, and structured coding lessons designed for absolute beginners.

Module 9

Sealed Classes in Java

Learn how sealed classes control inheritance and define restricted class hierarchies.

🔒

1. What are Sealed Classes?

A sealed class is a Java class or interface that restricts which classes or interfaces are allowed to extend or implement it.

Sealed classes are useful when an application needs a controlled and known inheritance hierarchy.

Key idea: A sealed type explicitly defines which types are permitted to become direct subtypes.

2. Java Version

Java Version Sealed Classes
Java 15 First preview
Java 16 Second preview
Java 17 Standard feature

3. Basic Sealed Class Syntax

The sealed keyword is followed by the permits clause that lists the allowed subclasses.

Java
public sealed class Vehicle
    permits Car, Bike {
}

public final class Car
    extends Vehicle {
}

public final class Bike
    extends Vehicle {
}

Here, only Car and Bike are permitted to directly extend Vehicle.

4. permits Keyword

The permits clause defines the direct subclasses that are allowed to inherit from the sealed type.

Java
sealed interface Payment
    permits CardPayment, CashPayment {
}

final class CardPayment
    implements Payment {
}

final class CashPayment
    implements Payment {
}
Benefit: The compiler knows the complete set of direct implementations.

5. final Subclasses

A permitted subclass can be declared final when it should not have any further subclasses.

Java
sealed class Animal
    permits Dog, Cat {
}

final class Dog
    extends Animal {
}

final class Cat
    extends Animal {
}

6. non-sealed Classes

A permitted subclass can use the non-sealed modifier to reopen the inheritance hierarchy.

Java
sealed class Vehicle
    permits Car, Truck {
}

non-sealed class Car
    extends Vehicle {
}

class SportsCar
    extends Car {
}

Because Car is non-sealed, other classes such as SportsCar can extend it.

7. A Sealed Subclass

A permitted subclass can itself remain sealed and restrict its own subclasses.

Java
sealed class Vehicle
    permits Car {
}

sealed class Car
    extends Vehicle
    permits ElectricCar {
}

final class ElectricCar
    extends Car {
}

8. Three Possible Subclass Modifiers

Every direct subclass of a sealed class must continue the inheritance policy using one of three modifiers:

  • final
  • sealed
  • non-sealed
Modifier Meaning
final No further inheritance is allowed.
sealed Inheritance continues but remains restricted.
non-sealed Inheritance is reopened.

9. Sealed Interfaces

Interfaces can also be sealed.

Java
public sealed interface Shape
    permits Circle, Rectangle {
}

final class Circle
    implements Shape {
}

final class Rectangle
    implements Shape {
}

10. Sealed Interfaces with Multiple Implementations

Java
sealed interface Payment
    permits CardPayment,
            UpiPayment,
            CashPayment {
}

final class CardPayment
    implements Payment {
}

final class UpiPayment
    implements Payment {
}

final class CashPayment
    implements Payment {
}

11. Location of Permitted Classes

In the common named-package case, permitted direct subclasses must belong to the same package as the sealed type.

The Java language also provides rules for unnamed modules and named modules, so the exact source-location rules depend on the module/package structure of the application.

12. Checking Sealed Types at Runtime

Java reflection can determine whether a class is sealed and inspect its permitted subclasses.

Java
sealed class Vehicle
    permits Car, Bike {
}

final class Car
    extends Vehicle {
}

final class Bike
    extends Vehicle {
}

public class Main {

    public static void main(String[] args) {

        System.out.println(
            Vehicle.class.isSealed()
        );

        Class<?>[] permitted =
            Vehicle.class.getPermittedSubclasses();

        for (Class<?> type : permitted) {

            System.out.println(
                type.getName()
            );
        }
    }
}

13. Sealed Classes and Pattern Matching

Sealed hierarchies work particularly well with modern pattern matching. Since the compiler knows the permitted subclasses, switch expressions can often be exhaustive without a default branch.

Java
sealed interface Shape
    permits Circle, Rectangle {
}

final class Circle
    implements Shape {
}

final class Rectangle
    implements Shape {
}

static String describe(Shape shape) {

    return switch (shape) {

        case Circle circle ->
            "Circle";

        case Rectangle rectangle ->
            "Rectangle";
    };
}
Important: The compiler can use the sealed hierarchy to verify that all permitted direct subtypes have been handled.

14. Sealed Classes for Domain Modeling

Sealed classes are useful when a domain has a fixed set of possible states or types.

Examples include:

  • Payment types
  • Notification types
  • Account states
  • Vehicle categories
  • Document types
  • Command types
  • Application results

15. Example: Result Hierarchy

Java
sealed interface Result
    permits Success, Failure {
}

record Success(String message)
    implements Result {
}

record Failure(String error)
    implements Result {
}

The hierarchy clearly communicates that the result can be either successful or failed.

16. Processing a Sealed Result

Java
static String process(Result result) {

    return switch (result) {

        case Success success ->
            "Success: " + success.message();

        case Failure failure ->
            "Failure: " + failure.error();
    };
}

17. Sealed Interfaces and Records

Records are implicitly final, which makes them convenient permitted implementations of sealed interfaces.

Java
sealed interface Command
    permits CreateUser, DeleteUser {
}

record CreateUser(
    String name
) implements Command {
}

record DeleteUser(
    long id
) implements Command {
}

18. Sealed Abstract Classes

A sealed class can also be abstract when the parent type should represent a common abstraction rather than be instantiated directly.

Java
public abstract sealed class Employee
    permits Developer, Manager {
}

final class Developer
    extends Employee {
}

final class Manager
    extends Employee {
}

19. Sealed Classes and Inheritance

Sealed classes do not remove inheritance. They make inheritance explicitly controlled.

Java
sealed class Employee
    permits Developer, Manager {
}

final class Developer
    extends Employee {
}

final class Manager
    extends Employee {
}
Difference: Normal inheritance is open by default. Sealed inheritance is restricted to an explicitly defined set of direct subtypes.

20. Advantages of Sealed Classes

  • Controls inheritance explicitly.
  • Improves domain modeling.
  • Provides stronger compile-time guarantees.
  • Works well with pattern matching.
  • Can make switch expressions exhaustive.
  • Makes permitted implementations easy to discover.
  • Reduces unintended extension of important abstractions.
  • Works well with records and modern Java features.

21. Limitations

  • Not suitable when an inheritance hierarchy intentionally needs to remain open.
  • Requires Java 17 or later as a standard language feature.
  • Direct subclasses must follow the sealed, final, or non-sealed rules.
  • Package and module rules must be respected.
  • Can be unnecessary for simple class hierarchies.

22. Sealed vs final vs non-sealed

Keyword Inheritance Behavior
final Stops inheritance completely.
sealed Allows only explicitly permitted subtypes.
non-sealed Reopens inheritance below that subtype.

23. Example 🌍🫠

An order processing system may have a fixed set of order states.

Java
sealed interface OrderStatus
    permits Pending,
            Confirmed,
            Cancelled {
}

record Pending()
    implements OrderStatus {
}

record Confirmed()
    implements OrderStatus {
}

record Cancelled()
    implements OrderStatus {
}

The application can then process the states using an exhaustive switch.

Java
static String message(
    OrderStatus status
) {

    return switch (status) {

        case Pending pending ->
            "Order is pending";

        case Confirmed confirmed ->
            "Order is confirmed";

        case Cancelled cancelled ->
            "Order is cancelled";
    };
}

24. Best Practices

  • Use sealed types when the set of direct subtypes is intentionally closed.
  • Use final for leaf classes that should not be extended.
  • Use non-sealed only when reopening inheritance is intentional.
  • Combine sealed hierarchies with pattern matching when appropriate.
  • Keep the permitted hierarchy small and meaningful.
  • Use records for simple immutable implementations when suitable.
  • Document why the hierarchy is intentionally restricted.

25. Interview Questions

A sealed class restricts which classes are allowed to directly extend it.

Sealed classes became a standard Java feature in Java 17.

The permits clause lists the classes or interfaces allowed to be direct subtypes of a sealed type.

A direct permitted subtype must be final, sealed, or non-sealed.

A sealed type continues to restrict its direct subtypes, while a non-sealed permitted subtype reopens inheritance.

Because the compiler knows the permitted subtype hierarchy, it can verify exhaustive handling in suitable switch expressions.

Summary

In this lesson, you learned:

  • What sealed classes are
  • The sealed keyword
  • The permits clause
  • final subclasses
  • sealed subclasses
  • non-sealed subclasses
  • Sealed interfaces
  • Sealed classes with records
  • Pattern matching with sealed hierarchies
  • Exhaustive switch expressions
  • Real-world domain modeling
  • Best practices and limitations