{"record":{"id":"fd16d1693f574d94","repo":"dotnet/efcore","slug":"the-mapping-strategy-mappingstrategy-specified","errorCode":null,"errorMessage":"The mapping strategy '{mappingStrategy}' specified on '{entityType}' is not supported for entity types with a discriminator.","messagePattern":"The mapping strategy '(.+?)' specified on '(.+?)' is not supported for entity types with a discriminator\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":2103,"sourceCode":"        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)\n        {\n            if (mappingStrategy is not null\n                and not RelationalAnnotationNames.TphMappingStrategy)\n            {\n                throw new InvalidOperationException(\n                    RelationalStrings.NonTphMappingStrategy(mappingStrategy, entityType.DisplayName()));\n            }\n\n            ValidateTphMapping(entityType, StoreObjectType.Table);\n            ValidateTphMapping(entityType, StoreObjectType.View);\n            ValidateTphMapping(entityType, StoreObjectType.Function);\n            ValidateTphMapping(entityType, StoreObjectType.InsertStoredProcedure);\n            ValidateTphMapping(entityType, StoreObjectType.DeleteStoredProcedure);\n            ValidateTphMapping(entityType, StoreObjectType.UpdateStoredProcedure);\n\n            ValidateDiscriminatorValues(entityType);\n        }\n        else\n        {\n            if (mappingStrategy != RelationalAnnotationNames.TpcMappingStrategy\n                && entityType.FindPrimaryKey() == null\n                && entityType.GetDirectlyDerivedTypes().Any())\n            {","sourceCodeStart":2085,"sourceCodeEnd":2121,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L2085-L2121","documentation":"A mapping strategy other than TPH (i.e. TPT or TPC) was configured on a hierarchy whose root has a discriminator property (HasDiscriminator/FindDiscriminatorProperty). Discriminator columns only make sense when all types share one table (TPH), so EF aborts. Thrown from ValidateInheritanceMapping when FindDiscriminatorProperty() != null and mappingStrategy != TPH.","triggerScenarios":"Calling both HasDiscriminator().IsComplete(true) and UseTptMappingStrategy()/UseTpcMappingStrategy() on the same hierarchy; migrating a hierarchy from TPH to TPT/TPC but leaving an explicit HasDiscriminator on the root.","commonSituations":"Porting a TPH model to TPT and forgetting to remove the discriminator configuration; applying a discriminator out of habit on a hierarchy that was switched to TPC; mixing attributes that imply a discriminator with a non-TPH strategy.","solutions":["Remove HasDiscriminator / the discriminator property configuration when using TPT or TPC.","Switch the strategy back to TPH if a discriminator column is actually desired.","Audit OnModelCreating for any discriminator-related calls when the strategy is non-TPH."],"exampleFix":"// before\nmodelBuilder.Entity<Person>()\n    .HasDiscriminator(p => p.Type).IsComplete(true)\n    .UseTptMappingStrategy();\n// after (TPC/TPT has no discriminator)\nmodelBuilder.Entity<Person>().UseTptMappingStrategy();\n// remove the discriminator property or stop configuring it","handlingStrategy":"validation","validationCode":"using (var ctx = new MyContext()) { ctx.Model.ToDebugString(); }\n// Assert no non-TPH strategy coexists with a discriminator property.\nforeach (var et in ctx.Model.GetEntityTypes().Where(e => e.BaseType == null))\n{\n    var s = (string?)et[Microsoft.EntityFrameworkCore.Metadata.RelationalAnnotationNames.MappingStrategy];\n    if (et.FindDiscriminatorProperty() != null && s is not null and not \"TPH\")\n        Debug.Fail($\"{et.Name} has a discriminator but uses '{s}', not TPH.\");\n}","typeGuard":null,"tryCatchPattern":"try { using var ctx = new MyContext(); _ = ctx.Model; }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"not supported for entity types with a discriminator\"))\n{ log.Error(\"Discriminator + non-TPH strategy; remove one: {Msg}\", ex.Message); throw; }","preventionTips":["When switching to TPT/TPC, remove all HasDiscriminator configuration from the root.","Prefer the UseXxxMappingStrategy() API over manually mixing discriminator configuration.","Cover the discriminator-vs-strategy invariant in a startup model-build test."],"tags":["ef-core","model-validation","inheritance","mapping-strategy","discriminator","tpt","tpc"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}