Optional: There are a lot of (a is Entity && b is Entity) checks here. This would not be necessary if deepEquals supported non-Entity objects. Then this block of conditionals could be simplified:

if (firstValue is List && secondValue is List) {
  if (firstValue.length != secondValue.length) return false;
  for (j = 0 -> len) {
    deepEquals(firstValue[j], secondValue[j]);
  }
} else if (!deepEquals(firstValue, secondValue)) {
  return false;
}