{"record":{"id":"8e2e73128cdfb400","repo":"dotnet/efcore","slug":"both-entitytype-and-otherentitytype-are-e","errorCode":null,"errorMessage":"Both '{entityType}' and  '{otherEntityType}' are explicitly mapped to the stored procedure '{sproc}' using the 'TPH' mapping strategy. Configure the stored procedure mapping on the root entity type, including all parameters for the derived types. See https://go.microsoft.com/fwlink/?linkid=2130430 for more information.","messagePattern":"Both '(.+?)' and  '(.+?)' are explicitly mapped to the stored procedure '(.+?)' using the 'TPH' mapping strategy\\. Configure the stored procedure mapping on the root entity type, including all parameters for the derived types\\. 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":2318,"sourceCode":"        var rootSproc = isSproc ? StoredProcedure.FindDeclaredStoredProcedure(rootEntityType, storeObjectType) : null;\n        var rootId = StoreObjectIdentifier.Create(rootEntityType, storeObjectType);\n        foreach (var entityType in rootEntityType.GetDerivedTypes())\n        {\n            var entityId = StoreObjectIdentifier.Create(entityType, storeObjectType);\n            if (entityId == null)\n            {\n                continue;\n            }\n\n            if (rootId == entityId)\n            {\n                if (rootSproc != null)\n                {\n                    var sproc = StoredProcedure.FindDeclaredStoredProcedure(entityType, storeObjectType);\n                    if (sproc != null\n                        && sproc != rootSproc)\n                    {\n                        throw new InvalidOperationException(\n                            RelationalStrings.StoredProcedureTphDuplicate(\n                                entityType.DisplayName(), rootEntityType.DisplayName(), rootId?.DisplayName()));\n                    }\n                }\n\n                continue;\n            }\n\n            switch (storeObjectType)\n            {\n                case StoreObjectType.Table:\n                    throw new InvalidOperationException(\n                        RelationalStrings.TphTableMismatch(\n                            entityType.DisplayName(), entityId.Value.DisplayName(),\n                            rootEntityType.DisplayName(), rootId?.DisplayName()));\n                case StoreObjectType.View:\n                    throw new InvalidOperationException(\n                        RelationalStrings.TphViewMismatch(","sourceCodeStart":2300,"sourceCodeEnd":2336,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L2300-L2336","documentation":"ValidateTphMapping handles stored procedures specially: when a derived type resolves to the SAME store object as the root (correct TPH behavior), EF still checks that the derived type did not declare its OWN stored procedure distinct from the root's. A TPH hierarchy must funnel all inserts/updates/deletes through one root sproc that carries parameters for every derived type; per-derived sprocs are illegal.","triggerScenarios":"Root has TPH (a discriminator) and a declared sproc (StoredProcedure.FindDeclaredStoredProcedure(root) is non-null); a derived type that maps to the same store object (rootId == entityId) ALSO declares a stored procedure for the same operation, and it is a different StoredProcedure instance than the root's.","commonSituations":"Copying .InsertStoredProcedure(...) calls from the root onto derived types in a TPH model; scaffolding sprocs per type then enabling TPH; misunderstanding that TPH sprocs must be centralized on the root.","solutions":["Remove the .InsertStoredProcedure/.UpdateStoredProcedure/.DeleteStoredProcedure configuration from the derived types and define it once on the root.","On the root sproc, include parameters for every derived type's extra properties (use .HasParameter or original-value parameters) so EF can route all operations through it.","If you genuinely need per-type sprocs, change the hierarchy to TPT/TPC where each type owns its sproc."],"exampleFix":"// before\nmodelBuilder.Entity<Base>().HasDiscriminator().InsertStoredProcedure(s => s.HasName(\"InsertBase\"));\nmodelBuilder.Entity<Derived>().InsertStoredProcedure(s => s.HasName(\"InsertDerived\")); // illegal in TPH\n\n// after\nmodelBuilder.Entity<Base>().HasDiscriminator()\n    .InsertStoredProcedure(s => s.HasName(\"InsertBase\")\n        .HasParameter(\"ExtraProp\") /* derived-only column */);","handlingStrategy":"validation","validationCode":"bool TphSprocsDeclaredOnRootOnly(DbContext context)\n{\n    foreach (var root in context.Model.GetEntityTypes()\n        .Where(e => e.BaseType == null && e.FindDiscriminatorProperty() != null))\n    {\n        foreach (var sot in new[] { StoreObjectType.InsertStoredProcedure, StoreObjectType.DeleteStoredProcedure, StoreObjectType.UpdateStoredProcedure })\n        {\n            if (StoredProcedure.FindDeclaredStoredProcedure(root, sot) is null) continue;\n            foreach (var d in root.GetDerivedTypes())\n            {\n                if (StoredProcedure.FindDeclaredStoredProcedure(d, sot) != null) return false;\n            }\n        }\n    }\n    return true;\n}","typeGuard":null,"tryCatchPattern":"try { _ = context.Model; }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"stored procedure\", StringComparison.Ordinal) && ex.Message.Contains(\"TPH\", StringComparison.Ordinal))\n{\n    throw new InvalidOperationException(\"In TPH, configure stored procedures only on the root and include all derived parameters there.\", ex);\n}","preventionTips":["In TPH, declare .InsertStoredProcedure/.UpdateStoredProcedure/.DeleteStoredProcedure on the root only.","Add parameters for every derived type's properties to the root sproc.","For per-type sprocs, switch the hierarchy to TPT/TPC instead."],"tags":["ef-core","model-validation","tph","stored-procedures","inheritance","relational"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}