dotnet/efcore · error · InvalidOperationException
The entity type '{entityType}' cannot be instantiated becaus
Error message
The entity type '{entityType}' cannot be instantiated because its corresponding CLR type is abstract, but the entity type was mapped to '{storeObject}' using the 'TPC' mapping strategy. Only instantiable types should be mapped. See https://go.microsoft.com/fwlink/?linkid=2130430 for more information. What it means
Stored-procedure mapping (Insert/Update/DeleteUsingStoredProcedure) is rejected for an abstract entity type that is mapped with the TPC (Table-per-Concrete-type) strategy. In TPC each concrete leaf type gets its own table, so an abstract base can never be instantiated or have a row written via a sproc; mapping a sproc onto it is a modeling error (RelationalEntityTypeBuilderExtensions.UseSproc.cs:934, RelationalStrings.AbstractTpc).
Source
Thrown at src/EFCore.Relational/Extensions/RelationalEntityTypeBuilderExtensions.UseSproc.cs:934
return entityTypeBuilder;
}
private static EntityTypeBuilder<TEntity> UseStoredProcedure<TEntity>(
EntityTypeBuilder<TEntity> entityTypeBuilder,
string? name,
string? schema,
StoreObjectType sprocType,
Action<StoredProcedureBuilder<TEntity>> buildAction)
where TEntity : class
{
Check.NotNull(buildAction);
var entityType = entityTypeBuilder.Metadata;
if (entityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy
&& !entityType.ClrType.IsInstantiable())
{
throw new InvalidOperationException(
RelationalStrings.AbstractTpc(entityType.DisplayName(), name ?? sprocType.ToString()));
}
var sprocBuilder = InternalStoredProcedureBuilder.HasStoredProcedure(
entityType, sprocType, name, schema);
buildAction(new StoredProcedureBuilder<TEntity>(sprocBuilder.Metadata, entityTypeBuilder));
return entityTypeBuilder;
}
private static OwnedNavigationBuilder UseStoredProcedure(
OwnedNavigationBuilder ownedNavigationBuilder,
string? name,
string? schema,
StoreObjectType sprocType,
Action<OwnedNavigationStoredProcedureBuilder> buildAction)
{
Check.NotNull(buildAction);View on GitHub (pinned to dbf9771522)
Solutions
- Move the *UsingStoredProcedure configuration to each concrete (non-abstract) derived entity type instead of the abstract base.
- Guard the call: only configure the sproc when entityType.ClrType.IsInstantiable() is true.
- If the base must define the mapping contract, use a shared partial OnModelCreating applied per concrete type, not on the abstract root.
Example fix
// before
modelBuilder.Entity<AnimalBase>() // AnimalBase is abstract, TPC
.ToTable(("Animals", "dbo"))
.UseTpcMappingStrategy()
.InsertUsingStoredProcedure("InsertAnimal", b => { ... });
// after (configure sprocs on each concrete type)
modelBuilder.Entity<AnimalBase>().UseTpcMappingStrategy();
modelBuilder.Entity<Dog>()
.InsertUsingStoredProcedure("InsertDog", b => { ... });
modelBuilder.Entity<Cat>()
.InsertUsingStoredProcedure("InsertCat", b => { ... }); Defensive patterns
Strategy: validation
Validate before calling
if (typeof(TEntity).IsAbstract
&& entityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy)
{
throw new InvalidOperationException("Abstract TPC base cannot be sproc-mapped.");
}
// only configure sprocs for instantiable types
if (typeof(TEntity).IsInstantiable())
{
builder.Entity<TEntity>().InsertUsingStoredProcedure(...);
} Prevention
- Apply sproc configuration per concrete type, not on an abstract base.
- When looping over entity types to configure sprocs, skip entityType.ClrType.IsAbstract.
- Keep TPC strategy configuration separate from sproc configuration on the base.
When it happens
Trigger: Calling InsertUsingStoredProcedure<TEntity>/UpdateUsingStoredProcedure<TEntity>/DeleteUsingStoredProcedure<TEntity> on an abstract base class TEntity whose hierarchy is configured with UseTpcMappingStrategy().
Common situations: Refactoring an existing TPH/TPT hierarchy to TPC while leaving the stored-procedure configuration on the abstract base; applying a shared configuration action to all entity types in a hierarchy without filtering out the abstract root; scaffolding/configuring sprocs generically across IEntityType instances.
Related errors
- Both entity type '{entityType1}' and '{entityType2}' were co
- Both '{entityType}' and '{otherEntityType}' are mapped to th
- Both '{entityType}' and '{otherEntityType}' are explicitly
- '{entityType}' is mapped to the stored procedure '{sproc}' w
- An Azure Cosmos DB container name is defined on entity type
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/6959193c8c20ea0e.
Report an issue: GitHub.