Normalize, then validate, then assign
A non-default instance is by construction normalized and valid — everywhere except the EF Core read path, which trusts values this same application already validated.
Rules declared once
MaxLength = 34 validates the value, sizes the EF Core column, and becomes the OpenAPI maxLength keyword. Anything added to [ValueObject<T>] feeds all three.
No reflection, no extra allocation
Holding 100 000 struct wrappers allocates exactly what holding 100 000 bare values allocates, to the byte. The generated equality and hashing keep dictionary lookups and sorts allocation-free too.