{"record":{"id":"3308cfbd66ddfb4d","repo":"dotnet/efcore","slug":"the-entity-type-entitytype-cannot-be-instantia-3308cf","errorCode":null,"errorMessage":"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.","messagePattern":"The entity type '(.+?)' cannot be instantiated because its corresponding CLR type is abstract, but the entity type was mapped to '(.+?)' using the 'TPC' mapping strategy\\. Only instantiable types should be mapped\\. See https://go\\.microsoft\\.com/fwlink/\\?linkid=2130430 for more information\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":2080,"sourceCode":"        IEntityType entityType,\n        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)\n    {\n        var mappingStrategy = (string?)entityType[RelationalAnnotationNames.MappingStrategy];\n        if (mappingStrategy != null)\n        {\n            ValidateMappingStrategy(entityType, mappingStrategy);\n            var storeObjectName = entityType.GetSchemaQualifiedTableName()\n                ?? entityType.GetSchemaQualifiedViewName()\n                ?? entityType.GetFunctionName()\n                ?? entityType.GetSqlQuery()\n                ?? entityType.GetInsertStoredProcedure()?.GetSchemaQualifiedName()\n                ?? entityType.GetDeleteStoredProcedure()?.GetSchemaQualifiedName()\n                ?? entityType.GetUpdateStoredProcedure()?.GetSchemaQualifiedName();\n            if (mappingStrategy == RelationalAnnotationNames.TpcMappingStrategy\n                && !entityType.ClrType.IsInstantiable()\n                && storeObjectName != null)\n            {\n                throw new InvalidOperationException(\n                    RelationalStrings.AbstractTpc(entityType.DisplayName(), storeObjectName));\n            }\n        }\n\n        if (entityType.BaseType != null)\n        {\n            if (mappingStrategy != null\n                && mappingStrategy != (string?)entityType.BaseType[RelationalAnnotationNames.MappingStrategy])\n            {\n                throw new InvalidOperationException(\n                    RelationalStrings.DerivedStrategy(entityType.DisplayName(), mappingStrategy));\n            }\n\n            return;\n        }\n\n        // Hierarchy mapping strategy must be the same across all types of mappings (only for root types)\n        if (entityType.FindDiscriminatorProperty() != null)","sourceCodeStart":2062,"sourceCodeEnd":2098,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L2062-L2098","documentation":"An entity type whose CLR type is abstract (cannot be instantiated) was mapped to a concrete store object (table/view/function/SQL query) under the TPC (Table-Per-Concrete-Type) mapping strategy. TPC generates one table per concrete type and inserts/queries instances of it, so an abstract type with a store object would be unreachable at runtime yet create a phantom table. EF rejects this at model validation.","triggerScenarios":"ValidateInheritanceMapping / ValidateMappingStrategy checks mappingStrategy == TpcMappingStrategy, !entityType.ClrType.IsInstantiable(), and a non-null store object (table/view/function/query/sproc); throws RelationalStrings.AbstractTpc. Triggered when an abstract base class in a TPC hierarchy has ToTable/ToView/etc.","commonSituations":"Marking the base class 'abstract' but leaving ToTable(\"Bases\") on it after switching to TPC; introducing an abstract intermediate type and not removing its mapping; TPC migration from TPH where the root entity had a table.","solutions":["Remove the ToTable/ToView/ToFunction/ToSqlQuery mapping from the abstract base type so it has no store object.","Make the CLR type concrete (non-abstract) if it genuinely needs its own table under TPC.","Move the store mapping to each concrete derived type instead of the abstract base."],"exampleFix":"// before\npublic abstract class Animal { public int Id { get; set; } }\nmodelBuilder.Entity<Animal>().ToTable(\"Animals\").UseTpcMappingStrategy();\n\n// after - abstract root has no table under TPC\nmodelBuilder.Entity<Animal>().UseTpcMappingStrategy();\nmodelBuilder.Entity<Dog>().ToTable(\"Dogs\");\nmodelBuilder.Entity<Cat>().ToTable(\"Cats\");","handlingStrategy":"validation","validationCode":"// For each TPC entity, ensure abstract types have no store object.\nforeach (var et in db.Model.GetEntityTypes())\n{\n    var strategy = et[RelationalAnnotationNames.MappingStrategy] as string;\n    if (strategy != RelationalAnnotationNames.TpcMappingStrategy) continue;\n    if (et.ClrType.IsAbstract)\n    {\n        var store = et.GetSchemaQualifiedTableName() ?? et.GetSchemaQualifiedViewName() ?? et.GetFunctionName() ?? et.GetSqlQuery();\n        if (store != null) Console.WriteLine($\"Abstract TPC type {et.Name} maps to {store}\");\n    }\n}","typeGuard":"static bool IsInstantiable(Type t) => !t.IsAbstract && !t.IsGenericTypeDefinition && !(t.IsGenericType && t.GetGenericArguments().Any(a => a.IsGenericParameter)) && t.GetConstructor(Type.EmptyTypes) != null || !t.IsAbstract;","tryCatchPattern":"try { _ = db.Model; } catch (InvalidOperationException ex) when (ex.Message.Contains(\"cannot be instantiated because its corresponding CLR type is abstract\") && ex.Message.Contains(\"TPC\")) { // remove the store mapping from the abstract type or make it concrete }","preventionTips":["Under TPC, never call ToTable/ToView on an abstract base type.","When switching a hierarchy to TPC, audit the previous root's mappings.","Add a startup model-build test for any TPC hierarchy."],"tags":["model-validation","inheritance","tpc","abstract","relational"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}