Enum wrapped in a struct
To use static instances of value types instead of plain enum isn't a strange thing. I can't discuss its merits because each case is different (for sure it's slightly slower but you will hardly notice that) but you can see it often (also in .NET Framework code.) Use it cum grano salis because IMO there aren't many use cases unless you want to emulate more powerful Java's enum.

What's wrong, in my opinion, is that you're mixing too many responsibilities inside the same class. Note that you also have code for representation (abbreviated enum value) which usually doesn't belong to domain.

Second point is to wrap the enum. If you use this pattern then you don't need an enum any more, just drop it and integer value (day of week) will have its own clear name.

Third point is initialization, you don't need a property, because Day is an immutable value type your code may be simplified to a static readonly field.

Let's imagine to declare your struct like this:

public struct Day
{
    public static readonly Day Monday = new Day(1);
    public static readonly Day Tuesday = new Day(2);

    private Day(int dayOfWeek)
    {
        _dayOfWeek = dayOfWeek;
    }

    private readonly int _dayOfWeek;
}


Now we have to make it easy to use during our debugging sessions (and integer value isn't so friendly). We have two options here, adding another field with long name (which eventually might hold also the short one) like this:

public static readonly Day Monday = new Day(nameof(Monday), 1);


Note that the main point is to keep everything in one single point. To add another day (!), for example Sunday, you need to change only one point in your code.

If you need it only for debugging then I'd avoid to override ToString() and I'd go with DebuggerDisplayAttribute but it's a matter of preference. ToString() is sometimes the mandatory choice for type conversion in many poor-designed libraries and I'd avoid to use it as debugging aid when I have better options.

[DebuggerDisplay("{_name}")]
public struct Day { /* */ }


Second option is to write a type ad-hoc for debugging purposes without polluting your value type with unused and heavy strings. Let's introduce DebuggerTypeProxyAttribute:

[DebuggerTypeProxy(typeof(DayDebugView))]
public struct Day { /* */ }


In DayDebugView you can put everything you need for debugging:

internal sealed class DayDebugView
{
    public DayDebugView(Day day)
    {
        _day;
    }

    public string Name
    {
        get
        {
            // Pseudo-code with some Reflection Magic
            // To get the static field name...
            return FindStaticFieldByValue(typeof(Day), _day)?.Name;
        }
    }

    private readonly Day _day;
}




Now you're done (in one way or another) with your debugging aid. If you need a presentation value then get rid of those hard-coded strings (because they're not localization friendly). Note that you might want, it depends on your usage pattern, use/implement IFormatProvider (in a separate class), implement IFormattable, implement a TypeConverter (in a separate class), implement IConvertible or use ValueConverterAttribute and implement IValueConverter. Which one is better/required depends on your UI requirements. For UI ToString() is just an abused handy method...



Add to all the above also code for comparison (at least overriding Equals() and implementing IEquatable&lt;T&gt; but probably also == and !=), eventually type conversions (to/from integers?), parsing to/from strings, serialization and...do you also need flags? Then few test to exercise you did everything correctly and you will ask yourself why you're not using a simple enum (with few lines of validation when it's an input.) Yes, sometimes you will need this structure but less often than you might imagine.