Skip to content

Settings.CollectionType

Simon Hughes edited this page Aug 30, 2026 · 1 revision

Settings.CollectionType and Settings.CollectionInterfaceType

The type a reverse navigation collection is declared as, and the type it is instantiated as.

Settings.CollectionInterfaceType Settings.CollectionType
Role The declared type The concrete type it is set to
Type string string
Default "ICollection" "List"
In Database.tt? Yes Yes

What they do

A one-to-many relationship gives the parent a collection of children. Two decisions go into that line:

public ICollection<Product> Products { get; set; }   // CollectionInterfaceType
...
Products = new List<Product>();                      // CollectionType

Both strings have <T> appended for you, so write "ICollection", not "ICollection<T>".

Example

ICollection and List (default)

    // Category
    public class Category
    {
        public int CategoryId { get; set; } // CategoryId (Primary key)
        public string CategoryName { get; set; } // CategoryName (length: 50)

        // Reverse navigation

        /// <summary>
        /// Child Products where [Product].[CategoryId] point to this entity (FK_Product_Category)
        /// </summary>
        public ICollection<Product> Products { get; set; } // Product.FK_Product_Category

        public Category()
        {
            Products = new List<Product>();
        }
    }

IList and ObservableCollection

Settings.CollectionInterfaceType = "IList";
Settings.CollectionType          = "ObservableCollection";
Settings.AdditionalNamespaces    = new List<string> { "System.Collections.ObjectModel" };
    // Category
    public class Category
    {
        public int CategoryId { get; set; } // CategoryId (Primary key)
        public string CategoryName { get; set; } // CategoryName (length: 50)

        // Reverse navigation

        /// <summary>
        /// Child Products where [Product].[CategoryId] point to this entity (FK_Product_Category)
        /// </summary>
        public IList<Product> Products { get; set; } // Product.FK_Product_Category

        public Category()
        {
            Products = new ObservableCollection<Product>();
        }
    }

When to change them

ObservableCollection for WPF, WinUI or MAUI, where the UI binds to the collection and needs change notification. This is the main reason anyone touches these settings, and it needs System.Collections.ObjectModel adding to Settings.AdditionalNamespaces.

HashSet if you add and look up children in memory a lot, and duplicates are impossible. EF Core is happy with a HashSet, and set semantics can be genuinely faster on a large collection.

IList if your code indexes into the collection. ICollection has no indexer, so order.Lines[0] does not compile - people usually discover this and then call .ToList() everywhere rather than changing the setting.

Leave them alone otherwise. ICollection is what EF Core's own scaffolding produces and what most EF documentation assumes.

Gotchas

The interface must be assignable from the concrete type. ICollection and List work; IList and HashSet do not compile, because HashSet<T> does not implement IList<T>. The generator does not check - you find out when the generated file fails to build.

You must supply the namespace yourself. ObservableCollection needs System.Collections.ObjectModel; anything of your own needs its own namespace. Add it to Settings.AdditionalNamespaces.

IEnumerable is a bad choice. EF Core needs to be able to add to the collection when it materialises the graph, and IEnumerable<T> gives it nothing to add to.

They apply to every reverse navigation, all or nothing. There is no per-relationship control.

Changing them does not change how EF queries. The collection type is a C# concern; the SQL is identical.

See also

Clone this wiki locally