{"record":{"id":"a5776418f61db69c","repo":"dotnet/efcore","slug":"hasshadowid-was-called-on-a-non-root-entity-type","errorCode":null,"errorMessage":"'HasShadowId' was called on a non-root entity type '{entityType}'. JSON 'id' configuration can only be made on the document root.","messagePattern":"'HasShadowId' was called on a non-root entity type '(.+?)'\\. JSON 'id' configuration can only be made on the document root\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs","lineNumber":565,"sourceCode":"    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    protected virtual void ValidateDiscriminatorMappings(\n        IEntityType entityType,\n        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)\n    {\n        if (!entityType.IsDocumentRoot()\n            && entityType.FindAnnotation(CosmosAnnotationNames.DiscriminatorInKey) != null)\n        {\n            throw new InvalidOperationException(CosmosStrings.DiscriminatorInKeyOnNonRoot(entityType.DisplayName()));\n        }\n\n        if (!entityType.IsDocumentRoot()\n            && entityType.FindAnnotation(CosmosAnnotationNames.HasShadowId) != null)\n        {\n            throw new InvalidOperationException(CosmosStrings.HasShadowIdOnNonRoot(entityType.DisplayName()));\n        }\n    }\n\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    protected override void ValidateIndex(\n        IIndex index,\n        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)\n    {\n        base.ValidateIndex(index, logger);\n\n        if (index.GetVectorIndexType() != null)\n        {\n            ValidateVectorIndex(index, logger);","sourceCodeStart":547,"sourceCodeEnd":583,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs#L547-L583","documentation":"Thrown by ValidateDiscriminatorMappings when a non-document-root entity type directly carries the HasShadowId annotation (set via HasShadowId). The __id shadow-property behavior is a document-root concern; derived types inherit the setting. The check uses FindAnnotation(CosmosAnnotationNames.HasShadowId) on non-root types.","triggerScenarios":"Calling HasShadowId(...) on an EntityTypeBuilder whose entity derives from a base entity (a non-root in an inheritance hierarchy).","commonSituations":"Running a shared 'configure shadow ids' helper across every entity in a hierarchy; legacy EF Core <9 behavior being re-added per entity after upgrade.","solutions":["Move the HasShadowId call to the root entity type.","Prefer the model-level HasShadowIds() on ModelBuilder over per-entity calls in hierarchies.","Guard shared config with `if (entityType.BaseType == null)` before applying HasShadowId."],"exampleFix":"// before\nmodelBuilder.Entity<Manager>().HasShadowId(); // Manager derives from Employee\n\n// after\nmodelBuilder.Entity<Employee>().HasShadowId();\n// or model-wide:\n// modelBuilder.HasShadowIds();","handlingStrategy":"validation","validationCode":"using var ctx = new MyContext();\nforeach (var e in ctx.Model.GetEntityTypes().Where(t => t.BaseType is not null))\n{\n    Debug.Assert(e.FindAnnotation(\"Cosmos:HasShadowId\") is null,\n        $\"{e.Name} (derived) must not call HasShadowId\");\n}","typeGuard":"static bool IsDocumentRoot(Microsoft.EntityFrameworkCore.Metadata.IEntityType e) => e.BaseType is null && e.IsDocumentRoot();","tryCatchPattern":"try { ctx.Model.GetModel(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"HasShadowId\"))\n{\n    logger.LogError(ex, \"HasShadowId was applied to a non-root entity\");\n    throw;\n}","preventionTips":["Prefer the model-level modelBuilder.HasShadowIds() over per-entity calls in hierarchies.","Only call HasShadowId on document roots; guard helpers with a root check.","Test that no derived type carries the HasShadowId annotation."],"tags":["cosmos","configuration","model-validation","json-id","inheritance"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}