{"record":{"id":"800ef22109d3ecf6","repo":"dotnet/efcore","slug":"both-entitytype-and-otherentitytype-are-ma-800ef2","errorCode":null,"errorMessage":"Both '{entityType}' and '{otherEntityType}' are mapped to the stored procedure '{sproc}'. All the entity types in a non-TPH hierarchy (one that doesn't have a discriminator) must be mapped to different stored procedures. See https://go.microsoft.com/fwlink/?linkid=2130430 for more information.","messagePattern":"Both '(.+?)' and '(.+?)' are mapped to the stored procedure '(.+?)'\\. All the entity types in a non-TPH hierarchy \\(one that doesn't have a discriminator\\) must be mapped to different stored procedures\\. 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":2251,"sourceCode":"                continue;\n            }\n\n            if (derivedTypes.TryGetValue(storeObject.Value, out var otherType))\n            {\n                switch (storeObjectType)\n                {\n                    case StoreObjectType.Table:\n                        throw new InvalidOperationException(\n                            RelationalStrings.NonTphTableClash(\n                                entityType.DisplayName(), otherType.DisplayName(), storeObject.Value.DisplayName()));\n                    case StoreObjectType.View:\n                        throw new InvalidOperationException(\n                            RelationalStrings.NonTphViewClash(\n                                entityType.DisplayName(), otherType.DisplayName(), storeObject.Value.DisplayName()));\n                    case StoreObjectType.InsertStoredProcedure:\n                    case StoreObjectType.DeleteStoredProcedure:\n                    case StoreObjectType.UpdateStoredProcedure:\n                        throw new InvalidOperationException(\n                            RelationalStrings.NonTphStoredProcedureClash(\n                                entityType.DisplayName(), otherType.DisplayName(), storeObject.Value.DisplayName()));\n                }\n            }\n\n            if (isTpc)\n            {\n                var rowInternalFk = entityType.FindDeclaredReferencingRowInternalForeignKeys(storeObject.Value)\n                    .FirstOrDefault();\n                if (rowInternalFk != null\n                    && entityType.GetDirectlyDerivedTypes().Any())\n                {\n                    throw new InvalidOperationException(\n                        RelationalStrings.TpcTableSharing(\n                            rowInternalFk.DeclaringEntityType.DisplayName(),\n                            storeObject.Value.DisplayName(),\n                            rowInternalFk.PrincipalEntityType.DisplayName()));\n                }","sourceCodeStart":2233,"sourceCodeEnd":2269,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L2233-L2269","documentation":"ValidateNonTphMapping applies the same uniqueness rule to stored procedures (Insert/Delete/Update): in a non-TPH hierarchy each type must own its own sproc, because there is no discriminator to route a single sproc's result to multiple types. When two types resolve to the same stored-procedure StoreObjectIdentifier, EF throws.","triggerScenarios":"Two sibling types in a TPT/TPC hierarchy both call .InsertStoredProcedure(s => s.HasName(\"Upsert\")) / Delete / Update with the same name, colliding in the derivedTypes dictionary for StoreObjectType.InsertStoredProcedure/DeleteStoredProcedure/UpdateStoredProcedure.","commonSituations":"Sharing one upsert/delete sproc across a hierarchy; copy-pasting stored-procedure configuration across derived types; scaffolding sprocs and forgetting to suffix per-type names.","solutions":["Give each type a distinct stored-procedure name per operation: .InsertStoredProcedure(s => s.HasName(\"Insert_Manager\")).","If you want one shared sproc for the whole hierarchy, use TPH and configure the sproc only on the root (see StoredProcedureTphDuplicate guidance).","Remove the redundant HasName on the derived type so its default name is used."],"exampleFix":"// before\nmodelBuilder.Entity<Manager>().InsertStoredProcedure(s => s.HasName(\"UpsertPerson\"));\nmodelBuilder.Entity<Employee>().InsertStoredProcedure(s => s.HasName(\"UpsertPerson\"));\n\n// after\nmodelBuilder.Entity<Manager>().InsertStoredProcedure(s => s.HasName(\"UpsertManager\"));\nmodelBuilder.Entity<Employee>().InsertStoredProcedure(s => s.HasName(\"UpsertEmployee\"));","handlingStrategy":"validation","validationCode":"bool NoNonTphSprocClash(DbContext context)\n{\n    foreach (var root in context.Model.GetEntityTypes()\n        .Where(e => e.BaseType == null && e.FindDiscriminatorProperty() == null && e.GetDerivedTypes().Any()))\n    {\n        foreach (var sot in new[] { StoreObjectType.InsertStoredProcedure, StoreObjectType.DeleteStoredProcedure, StoreObjectType.UpdateStoredProcedure })\n        {\n            var names = new HashSet<StoreObjectIdentifier>();\n            foreach (var et in root.GetDerivedTypesInclusive())\n            {\n                var so = StoreObjectIdentifier.Create(et, sot);\n                if (so.HasValue && !names.Add(so.Value)) return false;\n            }\n        }\n    }\n    return true;\n}","typeGuard":null,"tryCatchPattern":"try { _ = context.Model; }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"non-TPH hierarchy\", StringComparison.Ordinal) && ex.Message.Contains(\"stored procedure '\", StringComparison.Ordinal))\n{\n    throw new InvalidOperationException(\"Two types in a TPT/TPC hierarchy share a stored procedure. Give each type its own sproc name, or use TPH with a single root sproc.\", ex);\n}","preventionTips":["Name sprocs per concrete type in TPT/TPC (e.g. Insert_Manager).","For a shared sproc, switch to TPH and configure it on the root only.","Test the model build in CI to catch sproc-name collisions early."],"tags":["ef-core","model-validation","inheritance","tpt","tpc","stored-procedures","relational"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}