{"record":{"id":"16347d362f4336ae","repo":"dotnet/efcore","slug":"the-mapped-indexer-property-on-entity-type-entit","errorCode":null,"errorMessage":"The mapped indexer property on entity type '{entityType}' is not virtual. 'UseChangeTrackingProxies' requires all entity types to be public, unsealed, have virtual properties, and have a public or protected constructor. 'UseLazyLoadingProxies' requires only the navigation properties be virtual.","messagePattern":"The mapped indexer property on entity type '(.+?)' is not virtual\\. 'UseChangeTrackingProxies' requires all entity types to be public, unsealed, have virtual properties, and have a public or protected constructor\\. 'UseLazyLoadingProxies' requires only the navigation properties be virtual\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Proxies/Proxies/Internal/ProxyBindingRewriter.cs","lineNumber":183,"sourceCode":"                                if (!property.PropertyInfo!.SetMethod!.IsReallyVirtual())\n                                {\n                                    if (clrType.IsGenericType\n                                        && clrType.GetGenericTypeDefinition() == typeof(Dictionary<,>)\n                                        && clrType.GenericTypeArguments[0] == typeof(string))\n                                    {\n                                        if (entityType.GetProperties().Any(p => !p.IsPrimaryKey()))\n                                        {\n                                            throw new InvalidOperationException(\n                                                ProxiesStrings.DictionaryCannotBeProxied(\n                                                    clrType.ShortDisplayName(),\n                                                    entityType.DisplayName(),\n                                                    typeof(IDictionary<,>).MakeGenericType(clrType.GenericTypeArguments)\n                                                        .ShortDisplayName()));\n                                        }\n                                    }\n                                    else\n                                    {\n                                        throw new InvalidOperationException(\n                                            ProxiesStrings.NonVirtualIndexerProperty(entityType.DisplayName()));\n                                    }\n                                }\n                            }\n                        }\n                        else\n                        {\n                            if (property.PropertyInfo == null)\n                            {\n                                throw new InvalidOperationException(\n                                    ProxiesStrings.FieldProperty(property.Name, entityType.DisplayName()));\n                            }\n\n                            if (property.PropertyInfo.SetMethod?.IsReallyVirtual() == false)\n                            {\n                                throw new InvalidOperationException(\n                                    ProxiesStrings.NonVirtualProperty(property.Name, entityType.DisplayName()));\n                            }","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Proxies/Proxies/Internal/ProxyBindingRewriter.cs#L165-L201","documentation":"With UseChangeTrackingProxies enabled, an entity whose CLR type has a non-virtual indexer property (not the special Dictionary<string,> case handled separately) throws NonVirtualIndexerProperty (ProxyBindingRewriter.cs:181-185). The proxy must override the indexer setter to intercept changes.","triggerScenarios":"Enabling UseChangeTrackingProxies on an entity type that uses a custom indexer property whose indexer is non-virtual.","commonSituations":"Custom indexer-based entity types (e.g. dynamic property bags) used with change-tracking proxies.","solutions":["Make the indexer virtual on the CLR type so the proxy can override it.","Stop using change-tracking proxies for indexer-based entity types."],"exampleFix":"// before\npublic class DynBag\n{\n    public object? this[string key] { get; set; }\n}\n// after\npublic class DynBag\n{\n    public virtual object? this[string key] { get; set; }\n}","handlingStrategy":"validation","validationCode":"// Verify indexer setters are virtual before enabling change-tracking proxies:\nforeach (var pi in clrType.GetProperties())\n{\n    if (pi.GetIndexParameters().Length > 0 && pi.SetMethod?.IsVirtual != true)\n        throw new InvalidOperationException($\"{clrType.Name} indexer must be virtual for change-tracking proxies.\");\n}","typeGuard":"static bool IsVirtualIndexer(System.Reflection.PropertyInfo? pi)\n    => pi is not null && pi.GetIndexParameters().Length > 0 && pi.SetMethod?.IsVirtual == true;","tryCatchPattern":null,"preventionTips":["Make indexer properties virtual when using change-tracking proxies on indexer-based entities.","Avoid change-tracking proxies for non-virtual indexer entity types.","Design custom property-bag types with virtual indexers if proxying is required."],"tags":["ef-core","proxies","change-tracking-proxies","indexer","model-design"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}