Create dictionary with default immutable keys
When reading the title of the question, I wondered: "Why use a dict subclass when a regular class with __slots__ can do?". And judging by the interface, it seems that it may fit.

Slots defines attributes names that are reserved for the use as attributes for the instances of the class. However, no more attributes can be added to the instances when defining __slots__ on the class:

&gt;&gt;&gt; class Example:
...     __slots__ = ('a', 'b', 'c')
... 
&gt;&gt;&gt; e = Example()
&gt;&gt;&gt; e.a = 3
&gt;&gt;&gt; e.d = 4
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
AttributeError: 'Example' object has no attribute 'd'
&gt;&gt;&gt; e.a
3


However, __slots__ are not auto-populated and doing so at class level is prohibited:

&gt;&gt;&gt; class Example:
...   __slots__ = ('a', 'b', 'c')
...   a = 3
...   b = 4
...   c = 5
... 
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
ValueError: 'a' in __slots__ conflicts with class variable


You can, however, still define them in __init__:

class Bones:
    __slots__ = (
        'between_hips',
        'bicep_right',
        'bicep_left',
        'arm_right',
        'arm_left',
        'thigh_right',
        'thigh_left',
        'leg_right',
        'leg_left',
        'spine_lower',
        'spine_upper',
    )

    def __init__(self, default_value=0):
        for attribute in self.__slots__:
            setattr(self, attribute, default_value)


Now the only thing left is to add a dictionary-like interface (and/or inherit from collections.abc.Mapping):

    def __getitem__(self, key):
        return getattr(self, key)

    def __setitem__(self, key, value):
        setattr(self, key, value)

    def __len__(self):
        return len(self.__slots__)

    def __iter__(self):
        return iter(self.__slots__)

    def items(self):
        for attribute in self.__slots__:
            yield attribute, getattr(self, attribute)


Or not necessarily, since you can still access the __slots__ as regular attributes, it all depend on your use case.

Note that with this implementation, you can still delete values, which you try to prohibit in your original implementation:

&gt;&gt;&gt; b = Bones()
&gt;&gt;&gt; b.bicep_right
0
&gt;&gt;&gt; b['arm_left'] = 6
&gt;&gt;&gt; b.arm_left
6
&gt;&gt;&gt; del b['leg_left']
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
AttributeError: __delitem__
&gt;&gt;&gt; del b.leg_left
&gt;&gt;&gt; b.leg_left
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
AttributeError: leg_left


If you wish to prevent that, you need to define __delattr__ on your class as well:

    def __delattr__(self, key):
        raise AttributeError(key)