Sealed Classes

Vaibhav • September 10, 2025

In the last article, we explored abstract classes - a powerful way to define shared contracts and partial implementations across a class hierarchy. Now we turn to the opposite end of the inheritance spectrum: sealed classes. These are classes that cannot be inherited. While abstract classes encourage extension, sealed classes prevent it. This article explains why you might want to seal a class, how to do it, and what implications it has for design, performance, and maintainability.

What is a sealed class?

A sealed class is a class that cannot be used as a base class. You declare it using the sealed keyword. Once sealed, no other class can derive from it - not even within the same assembly.

sealed class Logger
{
    public void Log(string message)
    {
        Console.WriteLine($"Log: {message}");
    }
}

// This will cause a compile-time error
class FileLogger : Logger
{
    // Error: cannot derive from sealed class
}

In this example, Logger is sealed, so any attempt to inherit from it will result in a compiler error. This is a deliberate design choice - sealing a class communicates that its behavior is complete and should not be extended.

Sealed classes are often used to enforce immutability, prevent misuse, or optimize performance. They are common in security-sensitive or performance-critical code.

Why seal a class?

There are several reasons to seal a class. The most common include:

  • Design clarity: You want to signal that the class is complete and should not be extended.
  • Security: You want to prevent derived classes from overriding sensitive behavior.
  • Performance: The runtime can optimize method calls more aggressively for sealed classes.
  • Maintainability: You want to reduce the surface area for bugs by limiting inheritance.

For example, if you’re building a logging utility that writes to a file, and you don’t want users to override the file-writing logic, sealing the class ensures that your implementation remains untouched.

Seal classes that are not designed for extension. This makes your intent clear and protects your code from unintended inheritance.

Sealing methods vs sealing classes

You can also seal individual methods - but only in classes that are themselves derived from a base class. This is useful when you want to override a method but prevent further overriding in subclasses.

class Base
{
    public virtual void Display()
    {
        Console.WriteLine("Base Display");
    }
}

class Intermediate : Base
{
    public sealed override void Display()
    {
        Console.WriteLine("Intermediate Display");
    }
}

class Final : Intermediate
{
    // Error: cannot override sealed method
    // public override void Display() { ... }
}

In this example, Intermediate overrides Display() and seals it, preventing Final from overriding it again. This is a fine-grained way to control inheritance behavior.

You can only seal methods that are overrides. You cannot seal a method that is not already virtual or overridden.

Performance benefits of sealed classes

Sealed classes allow the runtime to make certain optimizations. For example, method calls on sealed classes can be devirtualized - meaning the runtime can skip the usual virtual dispatch and call the method directly. This improves performance, especially in tight loops or high-frequency code paths.

sealed class MathHelper
{
    public int Square(int x)
    {
        return x * x;
    }
}

Because MathHelper is sealed, the JIT compiler knows that Square() cannot be overridden. It can inline the method or optimize the call more aggressively.

The .NET JIT compiler uses sealed class information to eliminate virtual dispatch, which can lead to measurable performance gains in hot paths.

When not to seal a class

While sealing can be beneficial, it’s not always appropriate. Avoid sealing classes when:

  • You expect users to extend your class in their own applications.
  • You’re building a framework or library meant to be customized.
  • You want to support polymorphism across a hierarchy.

For example, if you’re building a UI framework and define a base class Control, you probably want developers to inherit from it to create custom controls. Sealing it would defeat that purpose.

Sealed classes and polymorphism

Sealed classes cannot participate in polymorphic hierarchies as base types. You can still use them as concrete types, but you lose the flexibility of substituting them in place of a base class or interface.

interface INotifier
{
    void Notify(string message);
}

sealed class EmailNotifier : INotifier
{
    public void Notify(string message)
    {
        Console.WriteLine($"Email: {message}");
    }
}

Here, EmailNotifier is sealed but still implements INotifier. You can use it polymorphically via the interface, but you cannot derive from it to create a SecureEmailNotifier.

Sealing and testing

One downside of sealing classes is that it can make unit testing harder. Many mocking frameworks rely on inheritance to create test doubles. If a class is sealed, you may need to use interfaces or dependency injection to test it effectively.

sealed class PaymentProcessor
{
    public bool Process(decimal amount)
    {
        // Real payment logic
        return true;
    }
}

// Hard to mock directly - use an interface instead
interface IPaymentProcessor
{
    bool Process(decimal amount);
}

class RealPaymentProcessor : IPaymentProcessor
{
    public bool Process(decimal amount)
    {
        return true;
    }
}

By abstracting the sealed class behind an interface, you regain testability without sacrificing the benefits of sealing.

If you seal a class, consider exposing its behavior through an interface to support testing and mocking.

Sealed classes in the .NET Framework

Many classes in the .NET Framework are sealed. For example:

  • System.String
  • System.Int32
  • System.DateTime
  • System.Console

These classes are sealed to prevent misuse and to allow the runtime to optimize them. You can still use them polymorphically via interfaces like IComparable or IFormattable, but you cannot derive from them.

Designing with sealed classes

When designing your own classes, ask yourself:

  • Is this class meant to be extended?
  • Does it expose virtual methods?
  • Would inheritance introduce risk or complexity?
  • Can I expose behavior via interfaces instead?

If the answer to most of these is “no,” sealing the class may be a good idea. It simplifies your design and communicates your intent clearly.

Summary

Sealed classes are a powerful tool for controlling inheritance in C#. They prevent extension, enable performance optimizations, and clarify design intent. You’ve learned how to declare sealed classes and methods, when to use them, and how they interact with polymorphism, testing, and interfaces. While sealing is not always appropriate, it’s a valuable technique for building robust, maintainable, and secure applications.

In the next article, we’ll explore Interface Basics - how to define contracts without implementation, and how interfaces enable flexible, decoupled design.