diff --git a/Build/phpstan/phpstan-baseline.neon b/Build/phpstan/phpstan-baseline.neon
index b953e3eedd3930fce12149f96e3e42d26ada64cb..0ac47d74f80386a2b983cc3aa4ccdadd0b3e5692 100644
--- a/Build/phpstan/phpstan-baseline.neon
+++ b/Build/phpstan/phpstan-baseline.neon
@@ -1770,16 +1770,6 @@ parameters:
 			count: 1
 			path: ../../typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Controller/ContentController.php
 
-		-
-			message: "#^PHPDoc type int\\|null of property ExtbaseTeam\\\\BlogExample\\\\Domain\\\\Model\\\\TtContent\\:\\:\\$pid is not covariant with PHPDoc type int of overridden property TYPO3\\\\CMS\\\\Extbase\\\\DomainObject\\\\AbstractDomainObject\\:\\:\\$pid\\.$#"
-			count: 1
-			path: ../../typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/TtContent.php
-
-		-
-			message: "#^PHPDoc type int\\|null of property ExtbaseTeam\\\\BlogExample\\\\Domain\\\\Model\\\\TtContent\\:\\:\\$uid is not covariant with PHPDoc type int of overridden property TYPO3\\\\CMS\\\\Extbase\\\\DomainObject\\\\AbstractDomainObject\\:\\:\\$uid\\.$#"
-			count: 1
-			path: ../../typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/TtContent.php
-
 		-
 			message: "#^Variable \\$expectations on left side of \\?\\? always exists and is not nullable\\.$#"
 			count: 1
diff --git a/typo3/sysext/belog/Classes/Domain/Model/LogEntry.php b/typo3/sysext/belog/Classes/Domain/Model/LogEntry.php
index c030e492f689fb307f3a7c03e62576dbafdbf7cd..9a72874024570437130845acc2b02b87d822fd42 100644
--- a/typo3/sysext/belog/Classes/Domain/Model/LogEntry.php
+++ b/typo3/sysext/belog/Classes/Domain/Model/LogEntry.php
@@ -33,7 +33,7 @@ class LogEntry extends AbstractEntity
     /**
      * Storage page ID of the log entry
      *
-     * @var int
+     * @var int<0, max>|null
      */
     protected $pid = 0;
 
diff --git a/typo3/sysext/extbase/Classes/DomainObject/AbstractDomainObject.php b/typo3/sysext/extbase/Classes/DomainObject/AbstractDomainObject.php
index 03a09eb4f27489af18acbce51727a9653647c9ce..757d44456d9b527b80b765287d9ff08a9e4d49bc 100644
--- a/typo3/sysext/extbase/Classes/DomainObject/AbstractDomainObject.php
+++ b/typo3/sysext/extbase/Classes/DomainObject/AbstractDomainObject.php
@@ -36,48 +36,59 @@ abstract class AbstractDomainObject implements DomainObjectInterface
     public const PROPERTY_VERSIONED_UID = '_versionedUid';
 
     /**
-     * @var int The uid of the record. The uid is only unique in the context of the database table.
+     * @var int<1, max>|null The uid of the record. The uid is only unique in the context of the database table.
+     * @todo introduce type declarations in 13.0 (possibly breaking)
      */
     protected $uid;
 
     /**
-     * @var int The uid of the localized record. Holds the uid of the record in default language (the translationOrigin).
+     * @var int<0, max>|null The uid of the localized record. Holds the uid of the record in default language (the translationOrigin).
+     *
+     * @internal
+     * @todo make private in 13.0 and expose value via getter
      */
-    protected $_localizedUid;
+    protected int|null $_localizedUid = null;
 
     /**
-     * @var int The uid of the language of the object. This is the id of the corresponding sing language.
+     * @var int<-1, max>|null The uid of the language of the object. This is the id of the corresponding sing language.
+     *
+     * @internal
+     * @todo make private in 13.0 and expose value via getter
      */
-    protected $_languageUid;
+    protected int|null $_languageUid = null;
 
     /**
-     * @var int The uid of the versioned record.
+     * The uid of the versioned record.
+     *
+     * @internal
+     * @todo make private in 13.0 and expose value via getter
      */
-    protected $_versionedUid;
+    protected int|null $_versionedUid = null;
 
     /**
-     * @var int The id of the page the record is "stored".
+     * @var int<0, max>|null The id of the page the record is "stored".
+     * @todo introduce type declarations in 13.0 (possibly breaking)
      */
     protected $pid;
 
     /**
      * TRUE if the object is a clone
      *
-     * @var bool
+     * @internal
      */
-    private $_isClone = false;
+    private bool $_isClone = false;
 
     /**
-     * @var array An array holding the clean property values. Set right after reconstitution of the object
+     * @var array<non-empty-string, mixed>
+     *
+     * @internal
      */
-    private $_cleanProperties = [];
+    private array $_cleanProperties = [];
 
     /**
-     * Getter for uid.
-     *
-     * @return int|null The uid or NULL if none set yet.
+     * @return int<1, max>|null
      */
-    public function getUid(): ?int
+    public function getUid(): int|null
     {
         if ($this->uid !== null) {
             return (int)$this->uid;
@@ -86,7 +97,7 @@ abstract class AbstractDomainObject implements DomainObjectInterface
     }
 
     /**
-     * Setter for the pid.
+     * @param int<0, max> $pid
      */
     public function setPid(int $pid): void
     {
@@ -94,11 +105,9 @@ abstract class AbstractDomainObject implements DomainObjectInterface
     }
 
     /**
-     * Getter for the pid.
-     *
-     * @return int|null The pid or NULL if none set yet.
+     * @return int<0, max>|null
      */
-    public function getPid(): ?int
+    public function getPid(): int|null
     {
         if ($this->pid === null) {
             return null;
@@ -107,13 +116,9 @@ abstract class AbstractDomainObject implements DomainObjectInterface
     }
 
     /**
-     * Reconstitutes a property. Only for internal use.
-     *
-     * @param mixed $propertyValue
-     * @return bool
      * @internal
      */
-    public function _setProperty(string $propertyName, $propertyValue)
+    public function _setProperty(string $propertyName, mixed $propertyValue): bool
     {
         if ($this->_hasProperty($propertyName)) {
             $this->{$propertyName} = $propertyValue;
@@ -123,27 +128,25 @@ abstract class AbstractDomainObject implements DomainObjectInterface
     }
 
     /**
-     * Returns the property value of the given property name. Only for internal use.
-     *
-     * @return mixed The propertyValue
      * @internal
      */
-    public function _getProperty(string $propertyName)
+    public function _getProperty(string $propertyName): mixed
     {
-        return $this->{$propertyName};
+        return $this->_hasProperty($propertyName) && isset($this->{$propertyName})
+            ? $this->{$propertyName}
+            : null;
     }
 
     /**
-     * Returns a hash map of property names and property values. Only for internal use.
+     * @return array<non-empty-string, mixed> a hash map of property names and property values.
      *
-     * @return array The properties
      * @internal
      */
     public function _getProperties(): array
     {
         $properties = get_object_vars($this);
         foreach ($properties as $propertyName => $propertyValue) {
-            if ($propertyName[0] === '_') {
+            if (str_starts_with($propertyName, '_')) {
                 unset($properties[$propertyName]);
             }
         }
@@ -151,10 +154,8 @@ abstract class AbstractDomainObject implements DomainObjectInterface
     }
 
     /**
-     * Returns the property value of the given property name. Only for internal use.
-     *
      * @param non-empty-string $propertyName
-     * @return bool TRUE bool true if the property exists, FALSE if it doesn't exist or NULL in case of an error.
+     *
      * @internal
      */
     public function _hasProperty(string $propertyName): bool
@@ -163,7 +164,7 @@ abstract class AbstractDomainObject implements DomainObjectInterface
     }
 
     /**
-     * Returns TRUE if the object is new (the uid was not set, yet). Only for internal use
+     * Returns TRUE if the object is new (the uid was not set, yet)
      *
      * @internal
      */
@@ -184,37 +185,34 @@ abstract class AbstractDomainObject implements DomainObjectInterface
             $this->_memorizePropertyCleanState($propertyName);
         } else {
             $this->_cleanProperties = [];
-            $properties = get_object_vars($this);
-            foreach ($properties as $propertyName => $propertyValue) {
-                if ($propertyName[0] === '_') {
-                    continue;
-                }
-                // Do not memorize "internal" properties
+            foreach ($this->_getProperties() as $propertyName => $propertyValue) {
                 $this->_memorizePropertyCleanState($propertyName);
             }
         }
     }
 
     /**
-     * Register a properties's clean state, e.g. after it has been reconstituted
+     * Register a property's clean state, e.g. after it has been reconstituted
      * from the database.
      *
-     * @param string $propertyName The name of the property to be memorized. If omitted all persistable properties are memorized.
+     * @param non-empty-string $propertyName The name of the property to be memorized. If omitted all persistable properties are memorized.
      */
-    public function _memorizePropertyCleanState($propertyName)
+    public function _memorizePropertyCleanState(string $propertyName): void
     {
-        $propertyValue = $this->{$propertyName};
+        $propertyValue = $this->_getProperty($propertyName);
         if (is_object($propertyValue)) {
-            $this->_cleanProperties[$propertyName] = clone $propertyValue;
+            $propertyValueClone = clone $propertyValue;
             // We need to make sure the clone and the original object
             // are identical when compared with == (see _isDirty()).
             // After the cloning, the Domain Object will have the property
             // "isClone" set to TRUE, so we manually have to set it to FALSE
             // again. Possible fix: Somehow get rid of the "isClone" property,
             // which is currently needed in Fluid.
-            if ($propertyValue instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject) {
-                $this->_cleanProperties[$propertyName]->_setClone(false);
+            if ($propertyValueClone instanceof AbstractDomainObject) {
+                $propertyValueClone->_setClone(false);
             }
+
+            $this->_cleanProperties[$propertyName] = $propertyValueClone;
         } else {
             $this->_cleanProperties[$propertyName] = $propertyValue;
         }
@@ -223,9 +221,9 @@ abstract class AbstractDomainObject implements DomainObjectInterface
     /**
      * Returns a hash map of clean properties and $values.
      *
-     * @return array
+     * @return array<non-empty-string, mixed>
      */
-    public function _getCleanProperties()
+    public function _getCleanProperties(): array
     {
         return $this->_cleanProperties;
     }
@@ -234,11 +232,11 @@ abstract class AbstractDomainObject implements DomainObjectInterface
      * Returns the clean value of the given property. The returned value will be NULL if the clean state was not memorized before, or
      * if the clean value is NULL.
      *
-     * @param string $propertyName The name of the property to be memorized.
-     * @return mixed The clean property value or NULL
+     * @param non-empty-string $propertyName The name of the property to be memorized.
+     *
      * @internal
      */
-    public function _getCleanProperty(string $propertyName)
+    public function _getCleanProperty(string $propertyName): mixed
     {
         return $this->_cleanProperties[$propertyName] ?? null;
     }
@@ -247,8 +245,8 @@ abstract class AbstractDomainObject implements DomainObjectInterface
      * Returns TRUE if the properties were modified after reconstitution
      *
      * @param non-empty-string|null $propertyName An optional name of a property to be checked if its value is dirty
-     * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\TooDirtyException
-     * @return bool
+     *
+     * @throws TooDirtyException
      */
     public function _isDirty(string|null $propertyName = null): bool
     {
@@ -258,26 +256,24 @@ abstract class AbstractDomainObject implements DomainObjectInterface
 
         if ($propertyName === null) {
             foreach ($this->_getCleanProperties() as $propertyName => $cleanPropertyValue) {
-                if ($this->isPropertyDirty($cleanPropertyValue, $this->{$propertyName}) === true) {
+                if ($this->isPropertyDirty($cleanPropertyValue, $this->_getProperty($propertyName)) === true) {
                     return true;
                 }
             }
-        } else {
-            if ($this->isPropertyDirty($this->_getCleanProperty($propertyName), $this->{$propertyName}) === true) {
-                return true;
-            }
+            return false;
         }
+
+        if ($this->isPropertyDirty($this->_getCleanProperty($propertyName), $this->_getProperty($propertyName)) === true) {
+            return true;
+        }
+
         return false;
     }
 
     /**
      * Checks the $value against the $cleanState.
-     *
-     * @param mixed $previousValue
-     * @param mixed $currentValue
-     * @return bool
      */
-    protected function isPropertyDirty($previousValue, $currentValue)
+    protected function isPropertyDirty(mixed $previousValue, mixed $currentValue): bool
     {
         // In case it is an object and it implements the ObjectMonitoringInterface, we call _isDirty() instead of a simple comparison of objects.
         // We do this, because if the object itself contains a lazy loaded property, the comparison of the objects might fail even if the object didn't change
@@ -286,7 +282,7 @@ abstract class AbstractDomainObject implements DomainObjectInterface
             if ($currentValue instanceof LazyLoadingProxy) {
                 $currentTypeString = $currentValue->_getTypeAndUidString();
             } elseif ($currentValue instanceof DomainObjectInterface) {
-                $currentTypeString = get_class($currentValue) . ':' . $currentValue->getUid();
+                $currentTypeString = $currentValue::class . ':' . $currentValue->getUid();
             }
 
             if ($currentTypeString !== null) {
@@ -294,12 +290,12 @@ abstract class AbstractDomainObject implements DomainObjectInterface
                 if ($previousValue instanceof LazyLoadingProxy) {
                     $previousTypeString = $previousValue->_getTypeAndUidString();
                 } elseif ($previousValue instanceof DomainObjectInterface) {
-                    $previousTypeString = get_class($previousValue) . ':' . $previousValue->getUid();
+                    $previousTypeString = $previousValue::class . ':' . $previousValue->getUid();
                 }
 
                 $result = $currentTypeString !== $previousTypeString;
             } elseif ($currentValue instanceof ObjectMonitoringInterface) {
-                $result = !is_object($previousValue) || $currentValue->_isDirty() || get_class($previousValue) !== get_class($currentValue);
+                $result = !is_object($previousValue) || $currentValue->_isDirty() || $previousValue::class !== $currentValue::class;
             } else {
                 // For all other objects we do only a simple comparison (!=) as we want cloned objects to return the same values.
                 $result = $previousValue != $currentValue;
@@ -310,12 +306,7 @@ abstract class AbstractDomainObject implements DomainObjectInterface
         return $result;
     }
 
-    /**
-     * Returns TRUE if the object has been cloned, FALSE otherwise.
-     *
-     * @return bool TRUE if the object has been cloned
-     */
-    public function _isClone()
+    public function _isClone(): bool
     {
         return $this->_isClone;
     }
@@ -326,27 +317,19 @@ abstract class AbstractDomainObject implements DomainObjectInterface
      * _isDirty check inside AbstractEntity work, but it is just a work-
      * around right now.
      *
-     * @param bool $clone
+     * @internal
      */
-    public function _setClone($clone)
+    public function _setClone(bool $clone)
     {
-        $this->_isClone = (bool)$clone;
+        $this->_isClone = $clone;
     }
 
-    /**
-     * Clone method. Sets the _isClone property.
-     */
     public function __clone()
     {
         $this->_isClone = true;
     }
 
-    /**
-     * Returns the class name and the uid of the object as string
-     *
-     * @return string
-     */
-    public function __toString()
+    public function __toString(): string
     {
         return static::class . ':' . (string)$this->uid;
     }
diff --git a/typo3/sysext/extbase/Classes/DomainObject/DomainObjectInterface.php b/typo3/sysext/extbase/Classes/DomainObject/DomainObjectInterface.php
index 0a5cdfae4470b10c087842445307d12306c152db..ce6a043bf0dbfbbc92175c513db26510c930f6be 100644
--- a/typo3/sysext/extbase/Classes/DomainObject/DomainObjectInterface.php
+++ b/typo3/sysext/extbase/Classes/DomainObject/DomainObjectInterface.php
@@ -31,23 +31,10 @@ use TYPO3\CMS\Extbase\Persistence\ObjectMonitoringInterface;
  */
 interface DomainObjectInterface extends ObjectMonitoringInterface
 {
-    /**
-     * Getter for uid.
-     *
-     * @return int The uid or NULL if none set yet.
-     */
     public function getUid(): ?int;
 
-    /**
-     * Setter for the pid.
-     */
     public function setPid(int $pid);
 
-    /**
-     * Getter for the pid.
-     *
-     * @return int The pid or NULL if none set yet.
-     */
     public function getPid(): ?int;
 
     /**
@@ -61,23 +48,17 @@ interface DomainObjectInterface extends ObjectMonitoringInterface
     public function _hasProperty(string $propertyName): bool;
 
     /**
-     * Reconstitutes a property. Only for internal use.
-     *
-     * @param mixed $value
+     * @param non-empty-string $propertyName
      */
-    public function _setProperty(string $propertyName, $value);
+    public function _setProperty(string $propertyName, mixed $value);
 
     /**
-     * Returns the property value of the given property name. Only for internal use.
-     *
-     * @return mixed The propertyValue
+     * @param non-empty-string $propertyName
      */
-    public function _getProperty(string $propertyName);
+    public function _getProperty(string $propertyName): mixed;
 
     /**
-     * Returns a hash map of property names and property values
-     *
-     * @return array The properties
+     * @return array<non-empty-string, mixed>
      */
     public function _getProperties(): array;
 
@@ -85,8 +66,8 @@ interface DomainObjectInterface extends ObjectMonitoringInterface
      * Returns the clean value of the given property. The returned value will be NULL if the clean state was not memorized before, or
      * if the clean value is NULL.
      *
-     * @param string $propertyName The name of the property to be memorized.
+     * @param non-empty-string $propertyName
      * @return mixed The clean property value or NULL
      */
-    public function _getCleanProperty(string $propertyName);
+    public function _getCleanProperty(string $propertyName): mixed;
 }
diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/TtContent.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/TtContent.php
index 7343df76d51f3bcf30011172c495508a2a2e2eda..2ffb80516df7e7a272049aee16357fe484456efa 100644
--- a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/TtContent.php
+++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/TtContent.php
@@ -28,12 +28,12 @@ use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
 class TtContent extends AbstractEntity
 {
     /**
-     * @var int|null
+     * @var int<1, max>|null
      */
     protected $uid;
 
     /**
-     * @var int|null
+     * @var int<0, max>|null
      */
     protected $pid;