{"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/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L2085-L2121","documentation":"Thrown by RelationalModelValidator.ValidateMappingStrategy when an entity type has a discriminator property configured (which implies TPH mapping) but a non-TPH mapping strategy (TPT or TPC) was set on it. A discriminator column only makes sense when the whole hierarchy shares one table, so combining a discriminator with TPT/TPC is contradictory and the model is rejected.","triggerScenarios":"An entity is configured with both HasDiscriminator()/HasDiscriminatorProperty() (or a discriminator property is otherwise detected via FindDiscriminatorProperty() != null) and modelBuilder.UseTptMappingStrategy() or UseTpcMappingStrategy() — or the strategy annotation is set on the root while a discriminator is still present.","commonSituations":"Migrating an existing TPH hierarchy to TPT/TPC but forgetting to remove the discriminator configuration; copy-pasting discriminator setup from a base entity while switching the hierarchy strategy; upgrading from older EF Core where discriminator + strategy coexisted differently.","solutions":["Remove the discriminator configuration (HasDiscriminator/HasDiscriminatorProperty) from the entity types when using UseTptMappingStrategy() or UseTpcMappingStrategy().","If you want the discriminator, switch the strategy back to TPH: modelBuilder.UseTphMappingStrategy() (the default).","Check for any [Discriminator] attributes or fluent HasDiscriminator calls on base and derived types and delete them."],"exampleFix":"// before\nmodelBuilder.Entity<Base>().HasDiscriminator<string>(\"Discriminator\");\nmodelBuilder.UseTptMappingStrategy(); // throws 420\n\n// after (TPT - remove discriminator)\nmodelBuilder.UseTptMappingStrategy();\n// no HasDiscriminator call","handlingStrategy":"validation","validationCode":"// Run before building/finalizing the model (e.g. in OnModelCreating or a unit test)\nforeach (var entityType in modelBuilder.Model.GetEntityTypes())\n{\n    var hasDiscriminator = entityType.FindDiscriminatorProperty() != null;\n    var strategy = entityType.GetMappingStrategy();\n    if (hasDiscriminator\n        && strategy is not null\n        && strategy != RelationalAnnotationNames.TphMappingStrategy)\n    {\n        throw new InvalidOperationException($\"{entityType.DisplayName()} has a discriminator but uses {strategy}; remove the discriminator or switch to TPH.\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When switching a hierarchy to TPT/TPC, search the configuration for HasDiscriminator and remove all such calls.","Prefer the UseTph/Tpt/TpcMappingStrategy() fluent API over hand-written annotations so the strategy and discriminator stay consistent.","Add a model-validation unit test that calls context.Model.ToString() or context.Database.EnsureCreated() in a test to fail fast at build time."],"tags":["ef-core","model-validation","mapping","inheritance","tph","tpt","tpc","discriminator"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}