Index: flexoentity/domain.py
===================================================================
--- flexoentity/domain.py	(revision 223c9d5f777e60d5529075baa850ea3cbe86f52f)
+++ flexoentity/domain.py	(revision 269fdc23e841020927c3cf9d45d5b59d1c54a8ff)
@@ -10,5 +10,5 @@
     """
     ENTITY_TYPE = EntityType.DOMAIN
-
+    subtype = "GENERAL"
     fullname: str = ""
     description: str = ""
@@ -25,7 +25,6 @@
         # Generate FlexOID only if missing
         if not getattr(self, "flexo_id", None):
-            domain_code = self.domain or "GEN"
             self.flexo_id = FlexOID.safe_generate(
-                domain=domain_code,
+                domain="GENERAL",
                 entity_type=EntityType.DOMAIN.value,   # 'D'
                 estate=EntityState.DRAFT.value,      # 'D'
@@ -41,4 +40,11 @@
         """
         return f"{self.fullname}|{self.classification}|{self.owner_id}"
+
+    @property
+    def domain_code(self) -> str:
+        """
+        I am self-domaining — I use my own subtype as domain code.
+        """
+        return self.subtype or "GENERAL"
 
     def to_dict(self):
Index: flexoentity/flexo_entity.py
===================================================================
--- flexoentity/flexo_entity.py	(revision 223c9d5f777e60d5529075baa850ea3cbe86f52f)
+++ flexoentity/flexo_entity.py	(revision 269fdc23e841020927c3cf9d45d5b59d1c54a8ff)
@@ -126,6 +126,4 @@
       - originator_id -> the UUID of the first creator
       - owner_id      -> the UUID of the current responsible person or system
-      - domain        -> FIXME: Explain reasons, why keep domain mutable. semantic
-                            domain hint (for filtering or indexing)
 
     I am designed to be traceable and reproducible:
@@ -147,5 +145,4 @@
     """
 
-    domain: str
     subtype: str = "GENERIC"
     flexo_id: Optional[FlexOID] = field(default=None)
@@ -190,12 +187,33 @@
         raise NotImplementedError("Subclasses must implement default()")
 
-    def domain_code(self) -> str:
-        """
-        I return a canonical domain code for serialization and ID generation.
-        As domains have their own domain code, I need to distinguish between Domains and
-        other FlexoEntities to avoid cyclic structures.
-        FIXME: Write a better comment
-        """
-        return self.domain.domain if hasattr(self.domain, "domain") else self.domain
+    @property
+    def domain_code(self):
+        return self.flexo_id.domain
+
+    @property
+    def default_domain_code(self):
+        return "GENERAL"
+
+    @classmethod
+    def with_domain(cls, domain, **kwargs):
+        """
+        I create an entity in a specific domain.
+        """
+
+        etype = getattr(cls, "ENTITY_TYPE", None)
+        if not etype:
+            raise ValueError(f"{cls.__name__} must define ENTITY_TYPE")
+
+        flexo_id = FlexOID.safe_generate(
+            domain=domain,
+            entity_type=etype.value,
+            estate=EntityState.DRAFT.value,
+            text=kwargs.get("text_seed", ""),
+            version=1,
+        )
+
+        obj = cls(flexo_id=flexo_id, **kwargs)
+        obj.fingerprint = obj._compute_fingerprint()
+        return obj
 
     def __post_init__(self):
@@ -220,5 +238,5 @@
         # Generate a new draft FlexOID
         self.flexo_id = FlexOID.safe_generate(
-            domain=self.domain_code(),
+            domain=self.default_domain_code,
             entity_type=etype.value,
             estate=EntityState.DRAFT.value,
@@ -238,5 +256,5 @@
     def to_dict(self):
         return {
-            "domain": self.domain_code(),
+            "domain": self.domain_code,
             "entity_type": self.entity_type.name,
             "state": self.state.name,
@@ -302,5 +320,5 @@
         if new_fp != self.fingerprint:
             self.fingerprint = new_fp
-            self.flexo_id = FlexOID.safe_generate(self.domain_code(),
+            self.flexo_id = FlexOID.safe_generate(self.domain_code,
                                                   self.entity_type.value,
                                                   self.state.value,
@@ -367,5 +385,5 @@
         """
         if self.state == EntityState.DRAFT:
-            new_fid = FlexOID.safe_generate(self.domain_code(),
+            new_fid = FlexOID.safe_generate(self.domain_code,
                                             self.entity_type.value,
                                             EntityState.APPROVED.value,
@@ -406,5 +424,5 @@
 
         new_fid = FlexOID.safe_generate(
-            self.domain_code(),
+            self.domain_code,
             self.entity_type.value,
             EntityState.PUBLISHED.value,
@@ -432,5 +450,5 @@
         self.origin = str(self.flexo_id)
         self.flexo_id = FlexOID.clone_new_base(
-            self.domain_code(),
+            self.domain_code,
             self.entity_type.value,
             EntityState.DRAFT.value,
@@ -499,5 +517,5 @@
 
             # Validate domain and ID coherence
-            if entity.domain and entity.domain_code() != entity.flexo_id.domain:
+            if entity.domain_code != entity.flexo_id.domain:
                 return False
             if entity.entity_type.value != entity.flexo_id.entity_type:
@@ -515,4 +533,5 @@
 
         except Exception as e:
+            print(e)
             return False
 
Index: tests/conftest.py
===================================================================
--- tests/conftest.py	(revision 223c9d5f777e60d5529075baa850ea3cbe86f52f)
+++ tests/conftest.py	(revision 269fdc23e841020927c3cf9d45d5b59d1c54a8ff)
@@ -45,10 +45,7 @@
         # If no FlexOID yet, generate a draft ID now.
         if not getattr(self, "flexo_id", None):
-            domain_code = (
-                self.domain.domain if isinstance(self.domain, Domain) else "GEN"
-            )
             self.flexo_id = FlexOID.safe_generate(
-                domain=domain_code,
-                entity_type=EntityType.ITEM.value,     # 'I'
+                domain=self.default_domain_code,
+                entity_type=SingleChoiceQuestion.ENTITY_TYPE.value,     # 'I'
                 estate=EntityState.DRAFT.value,        # 'D'
                 text=self.text_seed or self.text,
@@ -58,5 +55,5 @@
     @classmethod
     def default(cls):
-        return cls(domain=Domain(domain="GEN"))
+        return cls()
 
     def to_dict(self):
@@ -80,10 +77,8 @@
     @classmethod
     def from_dict(cls, data):
-        obj = cls(domain=Domain(domain="GEN"),
-            text=data.get("text", ""),
+        obj = cls(text=data.get("text", ""),
             options=[AnswerOption.from_dict(o) for o in data.get("options", [])],
         )
         # restore FlexoEntity core fields
-        obj.domain = data.get("domain")
         if "flexo_id" in data:
             obj.flexo_id = FlexOID.parsed(data["flexo_id"])
@@ -96,6 +91,5 @@
 @pytest.fixture
 def sample_question():
-    q = SingleChoiceQuestion(domain=Domain.default(),
-                             text="What is 2 + 2?",
+    q = SingleChoiceQuestion(text="What is 2 + 2?",
                              options=[])
     q._update_fingerprint()
Index: tests/test_id_lifecycle.py
===================================================================
--- tests/test_id_lifecycle.py	(revision 223c9d5f777e60d5529075baa850ea3cbe86f52f)
+++ tests/test_id_lifecycle.py	(revision 269fdc23e841020927c3cf9d45d5b59d1c54a8ff)
@@ -12,5 +12,4 @@
     assert q.flexo_id.version == 1
     assert FlexoEntity.verify_integrity(q)
-
 
 def test_approval_does_not_bump_version(sample_question):
Index: tests/test_id_stress.py
===================================================================
--- tests/test_id_stress.py	(revision 223c9d5f777e60d5529075baa850ea3cbe86f52f)
+++ tests/test_id_stress.py	(revision 269fdc23e841020927c3cf9d45d5b59d1c54a8ff)
@@ -33,5 +33,5 @@
     ids = []
     for seed in seeds:
-        oid = FlexOID.safe_generate(domain.domain, entity_type.value, estate.value, seed, repo=repo)
+        oid = FlexOID.safe_generate(domain.domain_code, entity_type.value, estate.value, seed, repo=repo)
         assert isinstance(oid, FlexOID)
         ids.append(str(oid))
@@ -60,6 +60,6 @@
     text = "identical question text"
 
-    id1 = FlexOID.generate(domain.domain, entity_type.value, estate.value, text)
-    id2 = FlexOID.generate(domain.domain, entity_type.value, estate.value, text)
+    id1 = FlexOID.generate(domain.domain_code, entity_type.value, estate.value, text)
+    id2 = FlexOID.generate(domain.domain_code, entity_type.value, estate.value, text)
     # IDs must be identical because generation is deterministic
     assert id1 == id2
@@ -75,7 +75,7 @@
 #     seed = "reproducibility test seed"
 
-#     id1 = FlexOID.generate(domain.domain, entity_type.value, estate.value, seed)
+#     id1 = FlexOID.generate(domain.domain_code, entity_type.value, estate.value, seed)
 #     FlexOID._seen_hashes.clear()
-#     id2 = FlexOID.generate(domain.domain, entity_type.value, estate.value, seed)
+#     id2 = FlexOID.generate(domain.domain_code, entity_type.value, estate.value, seed)
 
 #     assert id1 == id2
