Imagine you have a class called PaymentProcessor. Perfectly reasonable class, validated a payment, called a gateway, logged the result. There were six other classes inheriting from it across the codebase: PaymentProcessorV2, LegacyPaymentProcessor, TestPaymentProcessor.
Imagine someone had overridden ProcessPayment() in one subclass to skip validation, three years earlier. That override was still there, silently running in production, because nothing stopped anyone from inheriting from PaymentProcessor and quietly changing its behavior.
What sealed Actually Does
sealed is refreshingly simple in mechanics, even though the decision to use it isn't always simple. Put sealed on a class, and no other class can inherit from it, full stop.
public sealed class PaymentProcessor
{
public void ProcessPayment(decimal amount)
{
// validate, call gateway, log
}
}
public class FraudulentBypass : PaymentProcessor // ERROR: cannot derive from sealed class
{
}
That’s it. There’s no partial sealing, no “sealed except for this one class.” Once a class is sealed, the inheritance chain for it stops there, permanently, for every consumer of that code.
You can also seal an individual overridden method, which is a slightly different:
public class BaseProcessor
{
public virtual void Validate() { /* ... */ }
}
public class StandardProcessor : BaseProcessor
{
public sealed override void Validate()
{
// final implementation, no further overrides allowed
}
}
public class CustomProcessor : StandardProcessor
{
public override void Validate() { } // ERROR: Validate() is sealed here
}
This lets you allow inheritance generally, while locking down one specific method that absolutely must not change further down the hierarchy.
Useful when a base class needs to stay extensible, but one particular piece of behavior (say, a security check) has to be guaranteed identical for every subclass.
Why You’d Actually Choose to Seal Something
1. You’re Protecting Invariants That Inheritance Could Break
This was our PaymentProcessor problem exactly. The class had assumptions baked into it, payments always get validated, results always get logged, that only held true because nobody could override the methods that enforced them. The moment inheritance is possible, any guarantee your class makes is only a guarantee "unless someone overrides it," which in a large enough codebase, eventually happens.
Sealing a class is a way of saying, explicitly, in code: this behavior is final, don’t build on top of it, don’t reach into it, use it as is.
2. Security and Sensitive Classes
Anything dealing with authentication, cryptography, payment handling, or validation logic is a strong candidate for sealing. If a class enforces “always hash the password before storing it,” an unsealed class invites someone to subclass it and override the one method that does the hashing. Sealing removes that possibility entirely, rather than relying on code review to catch it every single time.
3. Performance (When Calling Methods)
The JIT compiler can make certain optimizations on sealed classes that it can’t make on classes open to inheritance. When you call a method on a sealed class, the runtime knows there’s no possibility of a derived class overriding that method, so it can sometimes skip virtual method dispatch (the runtime lookup of “which actual implementation should run”) and call the method directly, or even inline it.
4. Many Sealed Types Already Exist
string is sealed. System.Random isn't. When Microsoft seals a type in the base class library, it's usually because that type's internal behavior (string immutability being the obvious example) would be fundamentally broken if someone could subclass it and violate that guarantee.
Sealed isn't about restricting people for the sake of it, it's a promise that a class's behavior is complete and final, and you should make that promise exactly when inheritance would let someone silently break something your class depends on being true.

Join the conversation! Your thoughts help the community grow.