Anonymous types allow the creation of objects without having to explicitly define their types ahead of time, while maintaining static type checking.
var anon = new { Value = 1 };
Console.WriteLine(anon.Id); // compile time error
Conversely, dynamic
has dynamic type checking, opting for runtime errors, instead of compile-time errors.
dynamic val = "foo";
Console.WriteLine(val.Id); // compiles, but throws runtime error