dotnet/efcore · error · InvalidOperationException

JsonCantNavigateToParentEntity

JsonCantNavigateToParentEntity

Error message

Navigation from JSON-mapped entity '{jsonEntity}' to its parent entity '{parentEntity}' using navigation '{navigation}' is not supported. Entities mapped to JSON can only navigate to their children.

What it means

Thrown by JsonQueryExpression.BindStructuralProperty (JsonQueryExpression.cs:171) when the navigation being bound is a dependent-to-principal navigation (i.e. it points back to the parent entity). Entities mapped to JSON columns can only navigate to their children (deeper into the JSON), never back up to a parent entity stored in a separate table (issue #28645). EF cannot express such a join from inside the JSON document, so it throws.

Source

Thrown at src/EFCore.Relational/Query/JsonQueryExpression.cs:171

    /// <param name="structuralProperty">The navigation or complex property to bind.</param>
    /// <returns>An JSON query expression for the target entity or complex type.</returns>
    public virtual JsonQueryExpression BindStructuralProperty(IPropertyBase structuralProperty)
    {
        switch (structuralProperty)
        {
            case INavigation navigation:
            {
                if (StructuralType is not IEntityType entityType)
                {
                    throw new UnreachableException("Navigation on complex JSON type");
                }

                Check.DebugAssert(KeyPropertyMap is not null);

                if (navigation.ForeignKey.DependentToPrincipal == navigation)
                {
                    // issue #28645
                    throw new InvalidOperationException(
                        RelationalStrings.JsonCantNavigateToParentEntity(
                            navigation.ForeignKey.DeclaringEntityType.DisplayName(),
                            navigation.ForeignKey.PrincipalEntityType.DisplayName(),
                            navigation.Name));
                }

                var targetEntityType = navigation.TargetEntityType;
                var newPath = Path.ToList();
                newPath.Add(new PathSegment(GetJsonElement(navigation).PropertyName!));

                var newKeyPropertyMap = new Dictionary<IProperty, ColumnExpression>();
                var targetPrimaryKeyProperties = targetEntityType.FindPrimaryKey()!.Properties.Take(KeyPropertyMap.Count);
                var sourcePrimaryKeyProperties = entityType.FindPrimaryKey()!.Properties.Take(KeyPropertyMap.Count);
                foreach (var (target, source) in targetPrimaryKeyProperties.Zip(sourcePrimaryKeyProperties, (t, s) => (t, s)))
                {
                    newKeyPropertyMap[target] = KeyPropertyMap[source];
                }

View on GitHub (pinned to dbf9771522)

Solutions

  1. Query from the parent side and navigate down into the JSON-mapped child (the supported direction): ctx.Parents.Select(p => p.JsonChild).
  2. If you must start from the child, load it and then look up the parent by key in a separate query rather than via the navigation.
  3. Consider mapping the entity to a regular table (not ToJson) if bidirectional navigation from child to parent is essential.
  4. Remove or avoid using the dependent-to-principal navigation in JSON-mapped queries.

Example fix

// before - navigating from a JSON-mapped owned entity back to its parent
var parents = ctx.Set<ContactInfo>() // ContactInfo is owned, mapped ToJson
    .Where(ci => ci.Phone == "555")
    .Select(ci => ci.ParentContact) // JsonCantNavigateToParentEntity
    .ToList();

// after - query from the parent and navigate down (supported direction)
var contacts = ctx.Contacts
    .Where(c => c.Details.Phone == "555")
    .ToList();
Defensive patterns

Strategy: validation

Validate before calling

// Query from the parent downward into JSON children (supported direction).
var q = ctx.Contacts.Where(c => c.Details.Phone == "555").ToList();
// Avoid: ctx.Set<ContactInfo>().Select(ci => ci.ParentContact) // not supported

Type guard

// Avoid dependent-to-principal navigations on JSON-mapped entities.
static bool IsParentNavigation(INavigation n)
    => n.ForeignKey.DependentToPrincipal == n && n.DeclaringEntityType.IsMappedToJson();

Prevention

When it happens

Trigger: Querying a JSON-mapped owned entity and traversing a navigation that points to its parent (the owning entity). E.g. ctx.Set<OwnedChildJsonEntity>()... .Select(c => c.Parent). The navigation is the FK's back-reference (DependentToPrincipal), which EF detects at line 168.

Common situations: Modeling an owned type mapped ToJson and then trying to navigate from it back to the owner; bidirectional navigation between a JSON-mapped owned type and its principal; querying the JSON entity directly and joining back to the parent.

Related errors


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/b03b7ec2a34fcafc. Report an issue: GitHub.