dotnet/efcore · error · InvalidOperationException
The type '{givenType}' cannot be mapped as a dictionary beca
Error message
The type '{givenType}' cannot be mapped as a dictionary because it does not implement '{dictionaryType}'. What it means
Thrown by StringDictionaryComparer.Compare when the compared object is not an IReadOnlyDictionary<string, TElement>. The Cosmos provider maps dictionary properties via this comparer and expects the runtime type to implement the read-only dictionary interface; anything else is a model/type mismatch. This is an internal EF Core API, so the error usually indicates the property's CLR type is not what the model declared.
Source
Thrown at src/EFCore.Cosmos/ChangeTracking/Internal/StringDictionaryComparer.cs:128
{
if (aDictionary.Count != bDictionary.Count)
{
return false;
}
foreach (var pair in aDictionary)
{
if (!bDictionary.TryGetValue(pair.Key, out var bValue)
|| !elementCompare(pair.Value, bValue))
{
return false;
}
}
return true;
}
throw new InvalidOperationException(
CosmosStrings.BadDictionaryType(
(a is IDictionary<string, TElement?> ? b : a).GetType().ShortDisplayName(),
typeof(IDictionary<,>).MakeGenericType(typeof(string), typeof(TElement)).ShortDisplayName()));
}
private static int GetHashCode(IEnumerable source, Func<TElement?, int> elementGetHashCode)
{
if (source is not IReadOnlyDictionary<string, TElement?> sourceDictionary)
{
throw new InvalidOperationException(
CosmosStrings.BadDictionaryType(
source.GetType().ShortDisplayName(),
typeof(IList<>).MakeGenericType(typeof(TElement)).ShortDisplayName()));
}
var hash = new HashCode();
foreach (var pair in sourceDictionary)View on GitHub (pinned to dbf9771522)
Solutions
- Ensure the property's CLR type implements IReadOnlyDictionary<string, TElement> (e.g., use Dictionary<string, T> which implements it).
- Align the element type T used in the model with the comparer's TElement.
- If the property should be a list/array, reconfigure it as a complex collection rather than a dictionary mapping.
Example fix
// before
public List<KeyValuePair<string, int>> Tags { get; set; } // mapped as dictionary
// after
public Dictionary<string, int> Tags { get; set; } // implements IReadOnlyDictionary<string,int> Defensive patterns
Strategy: type-guard
Validate before calling
if (value is not IReadOnlyDictionary<string, TElement>)
{
throw new InvalidOperationException($"{value?.GetType()} is not a string-keyed dictionary.");
} Type guard
static bool IsStringDictionary<TElement>(object? value)
=> value is IReadOnlyDictionary<string, TElement>; Prevention
- Use Dictionary<string, T> (or another IReadOnlyDictionary<string,T> implementer) for Cosmos dictionary properties.
- Keep the property's CLR type aligned with the model mapping after refactors.
- Add a model snapshot test that asserts dictionary properties map to the expected comparer.
When it happens
Trigger: A Cosmos-mapped property configured as a string-keyed dictionary whose runtime instance is a non-dictionary collection (e.g., a List<T>, array, or a custom type that does not implement IReadOnlyDictionary<string, T>). Also when TElement mismatches the comparer's generic argument after a model change.
Common situations: Changing a property from Dictionary<string,T> to List<T> (or vice versa) without updating the model configuration. Deserializing JSON into a POCO that does not implement the dictionary interface but is mapped as one. Version upgrades where the comparer's required interface changed.
Related errors
- The value '{value}' provided for argument '{argumentName}' m
- Cosmos-specific methods can only be used when the context is
- The '{methodName}' method is not supported because the query
- The partition key value supplied for '{propertyType}' proper
- A full-text index on '{entityType}' is defined over multiple
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/b50bbb0573de3922.
Report an issue: GitHub.