dotnet/efcore · error · InvalidOperationException
Entity type '{entityType}' is sealed. 'UseChangeTrackingProx
Error message
Entity type '{entityType}' is sealed. 'UseChangeTrackingProxies' requires all entity types to be public, unsealed, have virtual properties, and have a public or protected constructor. 'UseLazyLoadingProxies' requires only the navigation properties be virtual. What it means
ProxyBindingRewriter throws ItsASeal when an entity type's CLR type is sealed and proxies are enabled (ProxyBindingRewriter.cs:72-75). Dynamic proxy generation (subclassing) cannot subclass a sealed type, so lazy-loading or change-tracking proxies are impossible for it.
Source
Thrown at src/EFCore.Proxies/Proxies/Internal/ProxyBindingRewriter.cs:74
IConventionContext<IConventionModelBuilder> context)
{
if (_options?.UseProxies == true)
{
modelBuilder.HasAnnotation(ProxyAnnotationNames.LazyLoading, _options.UseLazyLoadingProxies);
modelBuilder.HasAnnotation(ProxyAnnotationNames.ChangeTracking, _options.UseChangeTrackingProxies);
modelBuilder.HasAnnotation(ProxyAnnotationNames.CheckEquality, _options.CheckEquality);
foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
{
var clrType = entityType.ClrType;
if (clrType.IsAbstract)
{
continue;
}
if (clrType.IsSealed)
{
throw new InvalidOperationException(ProxiesStrings.ItsASeal(entityType.DisplayName()));
}
foreach (var navigationBase in entityType.GetDeclaredNavigations()
.Concat<IConventionNavigationBase>(entityType.GetDeclaredSkipNavigations()))
{
if (!navigationBase.IsShadowProperty())
{
if (_options.UseChangeTrackingProxies)
{
if (navigationBase.PropertyInfo == null)
{
throw new InvalidOperationException(
ProxiesStrings.FieldProperty(navigationBase.Name, entityType.DisplayName()));
}
if (navigationBase.PropertyInfo.SetMethod?.IsReallyVirtual() == false)
{
throw new InvalidOperationException(View on GitHub (pinned to dbf9771522)
Solutions
- Remove the 'sealed' modifier from the entity class so a proxy subclass can be generated.
- Stop using proxies for that entity type (drop UseChangeTrackingProxies/UseLazyLoadingProxies).
Example fix
// before
public sealed class Blog { public int Id { get; set; } }
// after
public class Blog { public int Id { get; set; } Defensive patterns
Strategy: validation
Validate before calling
// Reject sealed entity types before enabling proxies:
static bool CanProxy(Type t) => !t.IsSealed && t.IsClass && !t.IsAbstract;
foreach (var et in modelBuilder.Model.GetEntityTypes())
{
if (!CanProxy(et.ClrType))
throw new InvalidOperationException($"{et.ClrType} must not be sealed to use proxies.");
} Type guard
static bool IsProxyable(Type t) => t.IsClass && !t.IsAbstract && !t.IsSealed;
Prevention
- Do not seal entity classes when using proxies.
- Audit entity classes for the 'sealed' modifier before enabling proxies.
- Prefer abstract or non-sealed entity base types.
When it happens
Trigger: Enabling UseChangeTrackingProxies or UseLazyLoadingProxies when any non-abstract entity type is declared 'sealed'.
Common situations: Applying proxy options to an existing model whose entity classes are sealed, or a code generator/source generator emitting sealed entities.
Related errors
- Property '{property}' on entity type '{entityType}' is mappe
- Property '{entityType}.{property}' is not virtual. 'UseChang
- The type '{dictionaryType}' used for shared entity type '{en
- The mapped indexer property on entity type '{entityType}' is
- 'UseChangeTrackingProxies' and 'UseLazyLoadingProxies' each
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/4e84ed32547c6942.
Report an issue: GitHub.