Using a Generic Value Object in a DDD application
Using the code in your example along with the following article for reference

Representing a collection as a Value Object

Lets start with refactoring the City value object to use the improved ValueObject

public sealed class City : ValueObject&lt;City&gt; {

    public string Name { get; }
    public bool IsEnabled { get; }

    public City(string name, bool isEnabled) {
        Name = name;
        IsEnabled = isEnabled;
    } 

    protected override IEnumerable&lt;object&gt; GetEqualityComponents() {
        yield return Name; 
        yield return IsEnabled;
    }
}


Note how GetEqualityComponents was implemented. Reflection could also have been used to enumerate the properties as needed

return this.GetType().GetProperties().Select(propInfo =&gt; propInfo.GetValue(this, null);


There is room for improvement above and I will leave that as an exercise.

For collections, the GetEqualityComponents allows for a simplified approach of returning the items used to check equality.

public class CityList : ValueObject&lt;CityList&gt;, IEnumerable&lt;City&gt; {

    private List&lt;City&gt; _cities { get; }

    public CityList(IEnumerable&lt;City&gt; cities) {
        _cities = cities.ToList();
    }

    protected override IEnumerable&lt;object&gt; GetEqualityComponents() {
        return this.OrderBy(c =&gt; c.Name);
    }

    public IEnumerator&lt;City&gt; GetEnumerator() {
        return _cities.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator() {
        return GetEnumerator();
    }
}


Note that since the collection already implements IEnumerable one simple needs to return the desired enumeration that will be used to calculate equality.

GetEqualityComponents() proves to be a very convenient approach and really does improve and simplify how the ValueObject can be implemented. I initially though it to be a premature optimization attempt but having taken some time to review its potential I have changed my initial view of its function.

UPDATE from comments about the potential of using reflection.:


  The use of reflection automates and simplifies a repetitive task with
  a minor performance trade off. Caching the property/field info could
  help a little but I personally have had no issues with it performance
  wise. Also using reflection grabs all while using the yield like in
  the example you get to be selective of which ones to use for equality.
  You can make an extension method to get the best of both worlds and
  have options.


public static class ValueObjectExtensions {
    /// &lt;summary&gt;
    /// Uses reflection to extract all public properties from the target value object
    /// &lt;/summary&gt;
    public static IEnumerable&lt;object&gt; GetComponents&lt;T&gt;(this ValueObject&lt;T&gt; target)
        where T : ValueObject&lt;T&gt; {
        return target.GetType().GetProperties().Select(propInfo =&gt; propInfo.GetValue(target, null));
    }
}


and used like

protected override IEnumerable&lt;object&gt; GetEqualityComponents() {
   return this.GetComponents(); //&lt;-- calling extension method
}