Based on the issue description and my understanding of Django's architecture, the problem is clear:

1. When you create a model instance with an enum value like `MyChoice.FIRST_CHOICE`, Django stores the enum member directly in the instance's `__dict__`
2. When retrieved from the database, the raw string/int value is returned
3. This causes inconsistency where `str(my_object.my_str_value)` returns `'MyChoice.FIRST_CHOICE'` for created objects but `'first'` for retrieved objects

The fix needs to ensure that when a value is assigned to a field, if it's an enum member, the actual value is extracted. The proper place for this fix is in the `__set__` method of the field descriptor.

Looking at the Django codebase structure, the fix should be in `django/db/models/fields/__init__.py` where the `DeferredAttribute` class (or similar descriptor) handles value assignment.

Here's the patch:

--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -16,6 +16,7 @@ from django.core import checks, exceptions, validators
 from django.db import connection, connections, router
 from django.db.models.constants import LOOKUP_SEP
 from django.db.models.query_utils import DeferredAttribute, RegisterLookupMixin
+from django.db.models.enums import Choices
 from django.utils import timezone
 from django.utils.datastructures import DictWrapper
 from django.utils.dateparse import (
@@ -163,6 +164,8 @@ class Field(RegisterLookupMixin):
 
     def __set__(self, instance, value):
         instance.__dict__[self.attname] = value
+        if isinstance(value, Choices):
+            instance.__dict__[self.attname] = value.value
 
     def __reduce__(self):
         """