Repository: doctrine/orm (php)

Issue:
Fetched Entity with native Enum field with non empty changeSet (Enum <=> string)
### Bug Report

```php
// Order.php
    #[Column(type: Types::STRING, nullable: false, enumType: OrderStatus::class, options: ['charset' => 'utf8', 'collation' => 'utf8_unicode_ci'])]
    private OrderStatus $orderStatus;


// code.
$order = new Order();
$em->flush();
$em->clear();

$freshOrder = $em->createQueryBuilder()->select('o')->from(Order::class, 'o')->setMaxResults(1)->getQuery()->getSingleResult();

$uow->computeChangeSets();
$em->getUnitOfWork()->isScheduledForDelete($order); // returns true.
```

(The freshEneity is scheduled for the update because in the changeSet is 'strinngValue' of Enum::Foo.

But when I get the Entity like this

```php
$freshEntity = $this->getEntityManager()->find(Order::class, $orderId);
$uow->computeChangeSets();
$em->getUnitOfWork()->isScheduledForUpdate($order); // returns false, there is no update on fresh Entity.
```

<!-- Fill in the relevant information below to help triage your issue. -->

|    Q        |   A
|------------ | ------
| BC Break    | yes
| Version     | 2.13.x-dev

#### Summary

The $freshEntity with native Enum field shouldn't scheduled for updated
<!-- Provide a summary describing the problem you are experiencing. -->


the failing test case is here https://github.com/doctrine/orm/pull/10073 


Pull request:
Fix change set computation with enums
Fixes #10071 , uses test cases from #10073 by @mzk

My attempt at solving the issue. The `ReflectionEnumProperty::getValue()` method returns the value of the enum, while some hydrators pass an enum object in the data set to the `UnitOfWork::$originalEntityData` array.

The `SimpleObjectHydrator` doesn't convert strings into enums, while the `ObjectHydrator` (or to be more precise the `AbstractHydrator::gatherRowData()` method) does. Even though this doesn't seem to be causing any issues, the inconsistency seems unintentional to me, so if you think it should be fixed please let me know and I'll open a PR.

Patch:
diff --git a/.github/workflows/coding-standard.yml b/.github/workflows/coding-standard.yml
index d861ff8cf..04b255646 100644
--- a/.github/workflows/coding-standard.yml
+++ b/.github/workflows/coding-standard.yml
@@ -10,4 +10,4 @@ on:
 
 jobs:
   coding-standards:
-    uses: "doctrine/.github/.github/workflows/coding-standards.yml@2.0.0"
+    uses: "doctrine/.github/.github/workflows/coding-standards.yml@2.1.0"
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index b44eb5249..3beb186da 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -36,7 +36,7 @@ jobs:
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
         with:
           fetch-depth: 2
 
@@ -53,7 +53,7 @@ jobs:
         if: "${{ matrix.dbal-version != 'default' }}"
 
       - name: "Install dependencies with Composer"
-        uses: "ramsey/composer-install@v1"
+        uses: "ramsey/composer-install@v2"
         with:
           composer-options: "--ignore-platform-req=php+"
 
@@ -68,7 +68,7 @@ jobs:
             ENABLE_SECOND_LEVEL_CACHE: 1
 
       - name: "Upload coverage file"
-        uses: "actions/upload-artifact@v2"
+        uses: "actions/upload-artifact@v3"
         with:
           name: "phpunit-sqlite-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
           path: "coverage*.xml"
@@ -110,7 +110,7 @@ jobs:
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
         with:
           fetch-depth: 2
 
@@ -126,7 +126,7 @@ jobs:
         if: "${{ matrix.dbal-version != 'default' }}"
 
       - name: "Install dependencies with Composer"
-        uses: "ramsey/composer-install@v1"
+        uses: "ramsey/composer-install@v2"
         with:
           composer-options: "--ignore-platform-req=php+"
 
@@ -134,7 +134,7 @@ jobs:
         run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_pgsql.xml --coverage-clover=coverage.xml"
 
       - name: "Upload coverage file"
-        uses: "actions/upload-artifact@v2"
+        uses: "actions/upload-artifact@v3"
         with:
           name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
           path: "coverage.xml"
@@ -185,7 +185,7 @@ jobs:
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
         with:
           fetch-depth: 2
 
@@ -202,7 +202,7 @@ jobs:
           extensions: "${{ matrix.extension }}"
 
       - name: "Install dependencies with Composer"
-        uses: "ramsey/composer-install@v1"
+        uses: "ramsey/composer-install@v2"
         with:
           composer-options: "--ignore-platform-req=php+"
 
@@ -210,7 +210,7 @@ jobs:
         run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage.xml"
 
       - name: "Upload coverage file"
-        uses: "actions/upload-artifact@v2"
+        uses: "actions/upload-artifact@v3"
         with:
           name: "${{ github.job }}-${{ matrix.mariadb-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
           path: "coverage.xml"
@@ -261,7 +261,7 @@ jobs:
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
         with:
           fetch-depth: 2
 
@@ -278,7 +278,7 @@ jobs:
         if: "${{ matrix.dbal-version != 'default' }}"
 
       - name: "Install dependencies with Composer"
-        uses: "ramsey/composer-install@v1"
+        uses: "ramsey/composer-install@v2"
         with:
           composer-options: "--ignore-platform-req=php+"
 
@@ -293,7 +293,7 @@ jobs:
             ENABLE_SECOND_LEVEL_CACHE: 1
 
       - name: "Upload coverage files"
-        uses: "actions/upload-artifact@v2"
+        uses: "actions/upload-artifact@v3"
         with:
           name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
           path: "coverage*.xml"
@@ -313,7 +313,7 @@ jobs:
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
         with:
           fetch-depth: 2
 
@@ -324,7 +324,7 @@ jobs:
           ini-values: "zend.assertions=1"
 
       - name: "Install dependencies with Composer"
-        uses: "ramsey/composer-install@v1"
+        uses: "ramsey/composer-install@v2"
         with:
           dependency-versions: "${{ matrix.deps }}"
 
@@ -343,16 +343,16 @@ jobs:
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
         with:
           fetch-depth: 2
 
       - name: "Download coverage files"
-        uses: "actions/download-artifact@v2"
+        uses: "actions/download-artifact@v3"
         with:
           path: "reports"
 
       - name: "Upload to Codecov"
-        uses: "codecov/codecov-action@v1"
+        uses: "codecov/codecov-action@v3"
         with:
           directory: reports
diff --git a/.github/workflows/phpbench.yml b/.github/workflows/phpbench.yml
index 4924834a3..097473806 100644
--- a/.github/workflows/phpbench.yml
+++ b/.github/workflows/phpbench.yml
@@ -24,7 +24,7 @@ jobs:
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
         with:
           fetch-depth: 2
 
@@ -36,7 +36,7 @@ jobs:
           ini-values: "zend.assertions=1"
 
       - name: "Cache dependencies installed with composer"
-        uses: "actions/cache@v2"
+        uses: "actions/cache@v3"
         with:
           path: "~/.composer/cache"
           key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
diff --git a/.github/workflows/release-on-milestone-closed.yml b/.github/workflows/release-on-milestone-closed.yml
index 0e473ab47..2dfa3c026 100644
--- a/.github/workflows/release-on-milestone-closed.yml
+++ b/.github/workflows/release-on-milestone-closed.yml
@@ -7,7 +7,7 @@ on:
 
 jobs:
   release:
-    uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@2.0.0"
+    uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@2.1.0"
     secrets:
       GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }}
       GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }}
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index 830c96358..0cb0504a2 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -33,7 +33,7 @@ jobs:
 
     steps:
       - name: "Checkout code"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
 
       - name: "Install PHP"
         uses: "shivammathur/setup-php@v2"
@@ -50,7 +50,7 @@ jobs:
         if: "${{ matrix.persistence-version != 'default' }}"
 
       - name: "Install dependencies with Composer"
-        uses: "ramsey/composer-install@v1"
+        uses: "ramsey/composer-install@v2"
         with:
           dependency-versions: "highest"
 
@@ -78,7 +78,7 @@ jobs:
 
     steps:
       - name: "Checkout code"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
 
       - name: "Install PHP"
         uses: "shivammathur/setup-php@v2"
@@ -87,7 +87,7 @@ jobs:
           php-version: "${{ matrix.php-version }}"
 
       - name: "Install dependencies with Composer"
-        uses: "ramsey/composer-install@v1"
+        uses: "ramsey/composer-install@v2"
         with:
           dependency-versions: "highest"
 
diff --git a/composer.json b/composer.json
index cf7b249ae..58e765652 100644
--- a/composer.json
+++ b/composer.json
@@ -42,13 +42,13 @@
         "doctrine/annotations": "^1.13",
         "doctrine/coding-standard": "^9.0.2 || ^10.0",
         "phpbench/phpbench": "^0.16.10 || ^1.0",
-        "phpstan/phpstan": "~1.4.10 || 1.8.5",
+        "phpstan/phpstan": "~1.4.10 || 1.8.8",
         "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
         "psr/log": "^1 || ^2 || ^3",
         "squizlabs/php_codesniffer": "3.7.1",
         "symfony/cache": "^4.4 || ^5.4 || ^6.0",
         "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0",
-        "vimeo/psalm": "4.27.0"
+        "vimeo/psalm": "4.28.0"
     },
     "conflict": {
         "doctrine/annotations": "<1.13 || >= 2.0"
diff --git a/docs/en/reference/attributes-reference.rst b/docs/en/reference/attributes-reference.rst
index e7e015d4a..f0a8e2ec7 100644
--- a/docs/en/reference/attributes-reference.rst
+++ b/docs/en/reference/attributes-reference.rst
@@ -10,8 +10,8 @@ annotation metadata supported since the first version 2.0.
 Index
 -----
 
--  :ref:`#[AssociationOverride] <attrref_associationoverride]`
--  :ref:`#[AttributeOverride] <attrref_attributeoverride]`
+-  :ref:`#[AssociationOverride] <attrref_associationoverride>`
+-  :ref:`#[AttributeOverride] <attrref_attributeoverride>`
 -  :ref:`#[Column] <attrref_column>`
 -  :ref:`#[Cache] <attrref_cache>`
 -  :ref:`#[ChangeTrackingPolicy <attrref_changetrackingpolicy>`
@@ -27,7 +27,6 @@ Index
 -  :ref:`#[Id] <attrref_id>`
 -  :ref:`#[InheritanceType] <attrref_inheritancetype>`
 -  :ref:`#[JoinColumn] <attrref_joincolumn>`
--  :ref:`#[JoinColumns] <attrref_joincolumns>`
 -  :ref:`#[JoinTable] <attrref_jointable>`
 -  :ref:`#[ManyToOne] <attrref_manytoone>`
 -  :ref:`#[ManyToMany] <attrref_manytomany>`
@@ -179,7 +178,7 @@ Optional parameters:
     If not specified, default value is ``false``.
 
 -  **insertable**: Boolean value to determine if the column should be
-   included when inserting a new row into the underlying entities table. 
+   included when inserting a new row into the underlying entities table.
    If not specified, default value is true.
 
 -  **updatable**: Boolean value to determine if the column should be
diff --git a/docs/en/tutorials/embeddables.rst b/docs/en/tutorials/embeddables.rst
index 483e58d9d..507ef22d3 100644
--- a/docs/en/tutorials/embeddables.rst
+++ b/docs/en/tutorials/embeddables.rst
@@ -1,5 +1,5 @@
 Separating Concerns using Embeddables
--------------------------------------
+=====================================
 
 Embeddables are classes which are not entities themselves, but are embedded
 in entities and can also be queried in DQL. You'll mostly want to use them
diff --git a/lib/Doctrine/ORM/AbstractQuery.php b/lib/Doctrine/ORM/AbstractQuery.php
index 0d8610c11..d44d98c85 100644
--- a/lib/Doctrine/ORM/AbstractQuery.php
+++ b/lib/Doctrine/ORM/AbstractQuery.php
@@ -1077,7 +1077,8 @@ abstract class AbstractQuery
      *
      * @param ArrayCollection|mixed[]|null $parameters    The query parameters.
      * @param string|int|null              $hydrationMode The hydration mode to use.
-     * @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode The hydration mode to use.
+     * @psalm-param ArrayCollection<int, Parameter>|array<string, mixed>|null $parameters
+     * @psalm-param string|AbstractQuery::HYDRATE_*|null                      $hydrationMode The hydration mode to use.
      *
      * @return IterableResult
      */
diff --git a/lib/Doctrine/ORM/Event/LifecycleEventArgs.php b/lib/Doctrine/ORM/Event/LifecycleEventArgs.php
index 945989161..805f875db 100644
--- a/lib/Doctrine/ORM/Event/LifecycleEventArgs.php
+++ b/lib/Doctrine/ORM/Event/LifecycleEventArgs.php
@@ -42,7 +42,7 @@ class LifecycleEventArgs extends BaseLifecycleEventArgs
         Deprecation::trigger(
             'doctrine/orm',
             'https://github.com/doctrine/orm/issues/9875',
-            'Method %s() is deprecated and will be removed in Doctrine ORM 3.0. Use getObjectManager() instead.',
+            'Method %s() is deprecated and will be removed in Doctrine ORM 3.0. Use getObject() instead.',
             __METHOD__
         );
 
diff --git a/lib/Doctrine/ORM/LazyCriteriaCollection.php b/lib/Doctrine/ORM/LazyCriteriaCollection.php
index 212613084..5580f971e 100644
--- a/lib/Doctrine/ORM/LazyCriteriaCollection.php
+++ b/lib/Doctrine/ORM/LazyCriteriaCollection.php
@@ -76,12 +76,11 @@ class LazyCriteriaCollection extends AbstractLazyCollection implements Selectabl
     }
 
     /**
-     * Do an optimized search of an element
+     * {@inheritDoc}
      *
-     * @param object $element
-     * @psalm-param TValue $element
+     * Do an optimized search of an element
      *
-     * @return bool
+     * @template TMaybeContained
      */
     public function contains($element)
     {
diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php
index 8dac7210f..cf4dd0620 100644
--- a/lib/Doctrine/ORM/PersistentCollection.php
+++ b/lib/Doctrine/ORM/PersistentCollection.php
@@ -393,6 +393,8 @@ final class PersistentCollection extends AbstractLazyCollection implements Selec
 
     /**
      * {@inheritdoc}
+     *
+     * @template TMaybeContained
      */
     public function contains($element): bool
     {
diff --git a/lib/Doctrine/ORM/Tools/EntityGenerator.php b/lib/Doctrine/ORM/Tools/EntityGenerator.php
index 86ae90ed3..c92ecb9ce 100644
--- a/lib/Doctrine/ORM/Tools/EntityGenerator.php
+++ b/lib/Doctrine/ORM/Tools/EntityGenerator.php
@@ -527,11 +527,12 @@ public function __construct(<params>)
      * Sets the class fields visibility for the entity (can either be private or protected).
      *
      * @param string $visibility
-     * @psalm-param self::FIELD_VISIBLE_*
      *
      * @return void
      *
      * @throws InvalidArgumentException
+     *
+     * @psalm-assert self::FIELD_VISIBLE_* $visibility
      */
     public function setFieldVisibility($visibility)
     {
diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php
index 3a157c404..a3f179489 100644
--- a/lib/Doctrine/ORM/UnitOfWork.php
+++ b/lib/Doctrine/ORM/UnitOfWork.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace Doctrine\ORM;
 
+use BackedEnum;
 use DateTimeInterface;
 use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\Common\Collections\Collection;
@@ -743,6 +744,10 @@ class UnitOfWork implements PropertyChangedListener
 
                 $orgValue = $originalData[$propName];
 
+                if ($orgValue instanceof BackedEnum) {
+                    $orgValue = $orgValue->value;
+                }
+
                 // skip if value haven't changed
                 if ($orgValue === $actualValue) {
                     continue;
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index b53c1d684..b79dd9624 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -175,6 +175,11 @@ parameters:
 			count: 2
 			path: lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
 
+		-
+			message: "#^Method Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo\\:\\:fullyQualifiedClassName\\(\\) should return class\\-string\\|null but returns string\\|null\\.$#"
+			count: 1
+			path: lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
+
 		-
 			message: "#^Method Doctrine\\\\ORM\\\\Mapping\\\\NamingStrategy\\:\\:joinColumnName\\(\\) invoked with 2 parameters, 1 required\\.$#"
 			count: 2
@@ -501,7 +506,7 @@ parameters:
 			path: lib/Doctrine/ORM/Query/Parser.php
 
 		-
-			message: "#^Offset 'columns' on array\\{name\\: string, entities\\: array\\{\\}, columns\\: array\\}\\|array\\{name\\: string, entities\\: non\\-empty\\-array, columns\\: array\\} in isset\\(\\) always exists and is not nullable\\.$#"
+			message: "#^Offset 'columns' on array\\{name\\: string, entities\\: array, columns\\: array\\} in isset\\(\\) always exists and is not nullable\\.$#"
 			count: 1
 			path: lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php
 
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 3a99edf02..c95d04635 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<files psalm-version="4.27.0@faf106e717c37b8c81721845dba9de3d8deed8ff">
+<files psalm-version="4.28.0@52e96bea381e6cb07a672aefec791a5817694a26">
   <file src="lib/Doctrine/ORM/AbstractQuery.php">
     <DeprecatedClass occurrences="1">
       <code>IterableResult</code>
@@ -500,7 +500,7 @@
     </RedundantCastGivenDocblockType>
   </file>
   <file src="lib/Doctrine/ORM/Mapping/ClassMetadata.php">
-    <PropertyNotSetInConstructor occurrences="5">
+    <PropertyNotSetInConstructor occurrences="4">
       <code>ClassMetadata</code>
       <code>ClassMetadata</code>
       <code>ClassMetadata</code>
@@ -525,10 +525,6 @@
       <code>addNamedNativeQuery</code>
       <code>addNamedQuery</code>
     </DeprecatedMethod>
-    <DocblockTypeContradiction occurrences="2">
-      <code>! $definition</code>
-      <code>$definition</code>
-    </DocblockTypeContradiction>
     <InvalidArrayOffset occurrences="1">
       <code>$subClass-&gt;table[$indexType][$indexName]</code>
     </InvalidArrayOffset>
@@ -661,10 +657,9 @@
       <code>$this-&gt;associationMappings[$idProperty]['joinColumns']</code>
       <code>$this-&gt;associationMappings[$idProperty]['joinColumns']</code>
     </PossiblyUndefinedArrayOffset>
-    <PropertyNotSetInConstructor occurrences="5">
+    <PropertyNotSetInConstructor occurrences="4">
       <code>$idGenerator</code>
       <code>$namespace</code>
-      <code>$sequenceGeneratorDefinition</code>
       <code>$table</code>
       <code>$tableGeneratorDefinition</code>
     </PropertyNotSetInConstructor>
@@ -1427,9 +1422,6 @@
       <code>parent::setHint($name, $value)</code>
       <code>parent::setHydrationMode($hydrationMode)</code>
     </LessSpecificReturnStatement>
-    <MoreSpecificImplementedParamType occurrences="1">
-      <code>$parameters</code>
-    </MoreSpecificImplementedParamType>
     <MoreSpecificReturnType occurrences="2">
       <code>self</code>
       <code>self</code>
@@ -2718,9 +2710,6 @@
     <DocblockTypeContradiction occurrences="1">
       <code>class_exists($metadata-&gt;name)</code>
     </DocblockTypeContradiction>
-    <InvalidDocblock occurrences="1">
-      <code>public function setFieldVisibility($visibility)</code>
-    </InvalidDocblock>
     <PossiblyFalseArgument occurrences="2">
       <code>$last</code>
       <code>strrpos($metadata-&gt;name, '\\')</code>
@@ -2735,9 +2724,7 @@
       <code>(array) $metadata-&gt;table['options']</code>
       <code>(bool) $embeddablesImmutable</code>
     </RedundantCastGivenDocblockType>
-    <RedundantConditionGivenDocblockType occurrences="3">
-      <code>$metadata-&gt;sequenceGeneratorDefinition</code>
-      <code>$metadata-&gt;sequenceGeneratorDefinition</code>
+    <RedundantConditionGivenDocblockType occurrences="1">
       <code>isset($metadata-&gt;lifecycleCallbacks)</code>
     </RedundantConditionGivenDocblockType>
   </file>
@@ -2840,10 +2827,9 @@
       <code>$field['associationKey']</code>
       <code>isset($field['associationKey']) &amp;&amp; $field['associationKey']</code>
     </RedundantCondition>
-    <RedundantConditionGivenDocblockType occurrences="4">
+    <RedundantConditionGivenDocblockType occurrences="3">
       <code>$metadata-&gt;inheritanceType</code>
       <code>$metadata-&gt;inheritanceType</code>
-      <code>$sequenceDefinition</code>
       <code>isset($metadata-&gt;lifecycleCallbacks)</code>
     </RedundantConditionGivenDocblockType>
   </file>
diff --git a/psalm.xml b/psalm.xml
index 1da51a0a0..58dc30825 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -92,6 +92,8 @@
                 <!-- DBAL 3.2 forward compatibility -->
                 <file name="lib/Doctrine/ORM/Tools/Pagination/CountOutputWalker.php"/>
                 <file name="lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php"/>
+                <!-- https://github.com/vimeo/psalm/issues/8520 -->
+                <file name="lib/Doctrine/ORM/PersistentCollection.php"/>
             </errorLevel>
         </DocblockTypeContradiction>
         <InvalidArgument>


Test patch:
diff --git a/tests/Doctrine/Tests/Models/Cache/City.php b/tests/Doctrine/Tests/Models/Cache/City.php
index 13246d50a..09cf8703d 100644
--- a/tests/Doctrine/Tests/Models/Cache/City.php
+++ b/tests/Doctrine/Tests/Models/Cache/City.php
@@ -51,7 +51,7 @@ class City
      * @JoinColumn(name="state_id", referencedColumnName="id")
      */
     #[ORM\Cache]
-    #[ORM\ManyToOne(targetEntity: 'State', inversedBy: 'citities')]
+    #[ORM\ManyToOne(targetEntity: 'State', inversedBy: 'cities')]
     #[ORM\JoinColumn(name: 'state_id', referencedColumnName: 'id')]
     protected $state;
 
diff --git a/tests/Doctrine/Tests/ORM/Functional/EnumTest.php b/tests/Doctrine/Tests/ORM/Functional/EnumTest.php
index 9e53b8560..151067ef2 100644
--- a/tests/Doctrine/Tests/ORM/Functional/EnumTest.php
+++ b/tests/Doctrine/Tests/ORM/Functional/EnumTest.php
@@ -260,6 +260,46 @@ class EnumTest extends OrmFunctionalTestCase
         self::assertEqualsCanonicalizing([Unit::Gram, Unit::Meter], $result[0]->supportedUnits);
     }
 
+    public function testEnumChangeSetsSimpleObjectHydrator(): void
+    {
+        $this->setUpEntitySchema([Card::class]);
+
+        $card       = new Card();
+        $card->suit = Suit::Clubs;
+
+        $this->_em->persist($card);
+        $this->_em->flush();
+        $this->_em->clear();
+
+        $result = $this->_em->find(Card::class, $card->id);
+
+        $this->_em->getUnitOfWork()->computeChangeSets();
+
+        self::assertFalse($this->_em->getUnitOfWork()->isScheduledForUpdate($result));
+    }
+
+    public function testEnumChangeSetsObjectHydrator(): void
+    {
+        $this->setUpEntitySchema([Card::class]);
+
+        $card       = new Card();
+        $card->suit = Suit::Clubs;
+
+        $this->_em->persist($card);
+        $this->_em->flush();
+        $this->_em->clear();
+
+        $result = $this->_em->createQueryBuilder()
+            ->from(Card::class, 'c')
+            ->select('c')
+            ->getQuery()
+            ->getResult();
+
+        $this->_em->getUnitOfWork()->computeChangeSets();
+
+        self::assertFalse($this->_em->getUnitOfWork()->isScheduledForUpdate($result[0]));
+    }
+
     public function testFindByEnum(): void
     {
         $this->setUpEntitySchema([Card::class]);
diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php
index da847f347..181b7fad5 100644
--- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php
+++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC5684Test.php
@@ -125,7 +125,7 @@ class DDC5684Object
     /**
      * @var DDC5684ObjectIdType
      * @Id
-     * @Column(type=Doctrine\Tests\ORM\Functional\Ticket\DDC5684ObjectIdType::class)
+     * @Column(type=DDC5684ObjectIdType::class)
      * @GeneratedValue(strategy="AUTO")
      */
     public $id;
diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH6141Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH6141Test.php
index 6bb6baded..102609d93 100644
--- a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH6141Test.php
+++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH6141Test.php
@@ -153,8 +153,8 @@ class GH6141People
  * @InheritanceType("JOINED")
  * @DiscriminatorColumn(name="discr", type="gh6141people")
  * @DiscriminatorMap({
- *      Doctrine\Tests\ORM\Functional\Ticket\GH6141People::BOSS     = GH6141Boss::class,
- *      Doctrine\Tests\ORM\Functional\Ticket\GH6141People::EMPLOYEE = GH6141Employee::class
+ *      GH6141People::BOSS     = GH6141Boss::class,
+ *      GH6141People::EMPLOYEE = GH6141Employee::class
  * })
  */
 abstract class GH6141Person
diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7012Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7012Test.php
index 4421a4ce4..836f40ce2 100644
--- a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7012Test.php
+++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7012Test.php
@@ -58,7 +58,7 @@ class GH7012UserData
     /**
      * @var QuotedUser
      * @Id
-     * @OneToOne(targetEntity=Doctrine\Tests\Models\Quote\User::class)
+     * @OneToOne(targetEntity=QuotedUser::class)
      * @JoinColumn(name="`user-id`", referencedColumnName="`user-id`", onDelete="CASCADE")
      */
     public $user;
diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7512Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7512Test.php
index 253138ed6..fa5857027 100644
--- a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7512Test.php
+++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH7512Test.php
@@ -48,8 +48,8 @@ class GH7512Test extends OrmFunctionalTestCase
  * @Entity()
  * @InheritanceType("JOINED")
  * @DiscriminatorMap({
- *     "entitya"=Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityA::class,
- *     "entityB"=Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityB::class
+ *     "entitya"=GH7512EntityA::class,
+ *     "entityB"=GH7512EntityB::class
  * })
  */
 class GH7512EntityA
@@ -63,7 +63,7 @@ class GH7512EntityA
     public $id;
 
     /**
-     * @OneToMany(targetEntity="Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityC", mappedBy="entityA")
+     * @OneToMany(targetEntity="GH7512EntityC", mappedBy="entityA")
      * @var Collection<int, GH7512EntityC>
      */
     public $entityCs;
@@ -86,7 +86,7 @@ class GH7512EntityC
     public $id;
 
     /**
-     * @ManyToOne(targetEntity="Doctrine\Tests\ORM\Functional\Ticket\GH7512EntityA", inversedBy="entityCs")
+     * @ManyToOne(targetEntity="GH7512EntityA", inversedBy="entityCs")
      * @var GH7512EntityA
      */
     public $entityA;
diff --git a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php
index faaa05b9f..704799c9e 100644
--- a/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php
+++ b/tests/Doctrine/Tests/ORM/PersistentCollectionTest.php
@@ -21,6 +21,8 @@ use stdClass;
 use function array_keys;
 use function assert;
 use function method_exists;
+use function serialize;
+use function unserialize;
 
 /**
  * Tests the lazy-loading capabilities of the PersistentCollection and the initialization of collections.
@@ -286,4 +288,13 @@ class PersistentCollectionTest extends OrmTestCase
 
         $this->collection->clear();
     }
+
+    public function testItCanBeSerializedAndUnserializedBack(): void
+    {
+        $this->collection->add(new stdClass());
+        $collection = unserialize(serialize($this->collection));
+        $collection->add(new stdClass());
+        $collection[3] = new stdClass();
+        self::assertCount(3, $collection);
+    }
 }
diff --git a/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php b/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php
index 90dd6b4cd..c88de7e28 100644
--- a/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php
+++ b/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php
@@ -366,7 +366,7 @@ class DDC1649Two
 {
     /**
      * @var DDC1649One
-     * @Id @ManyToOne(targetEntity="DDC1649One")@JoinColumn(name="id", referencedColumnName="id")
+     * @Id @ManyToOne(targetEntity="DDC1649One")
      */
     public $one;
 }