diff --git a/build/target-repository/docs/rector_rules_overview.md b/build/target-repository/docs/rector_rules_overview.md
index a39279ad1d8..fdacc54a1a0 100644
--- a/build/target-repository/docs/rector_rules_overview.md
+++ b/build/target-repository/docs/rector_rules_overview.md
@@ -1,4 +1,4 @@
-# 369 Rules Overview
+# 370 Rules Overview
@@ -10,7 +10,7 @@
- [CodingStyle](#codingstyle) (28)
-- [DeadCode](#deadcode) (43)
+- [DeadCode](#deadcode) (44)
- [EarlyReturn](#earlyreturn) (9)
@@ -2886,6 +2886,29 @@ Remove `@param` docblock with same type as parameter type
+### RemoveUselessReadOnlyTagRector
+
+Remove useless `@readonly` annotation on native readonly type
+
+- class: [`Rector\DeadCode\Rector\Property\RemoveUselessReadOnlyTagRector`](../rules/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector.php)
+
+```diff
+ final class SomeClass
+ {
+- /**
+- * @readonly
+- */
+ private readonly string $name;
+
+ public function __construct(string $name)
+ {
+ $this->name = $name;
+ }
+ }
+```
+
+
+
### RemoveUselessReturnExprInConstructRector
Remove useless return Expr in `__construct()`
diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_class.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_class.php.inc
new file mode 100644
index 00000000000..df38cce3edb
--- /dev/null
+++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_class.php.inc
@@ -0,0 +1,32 @@
+
+-----
+
diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_param_construct.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_param_construct.php.inc
new file mode 100644
index 00000000000..1b9b8366114
--- /dev/null
+++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_param_construct.php.inc
@@ -0,0 +1,32 @@
+
+-----
+
diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_property.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_property.php.inc
new file mode 100644
index 00000000000..6d7f7b3d7ab
--- /dev/null
+++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/remove_on_property.php.inc
@@ -0,0 +1,34 @@
+name = $name;
+ }
+}
+
+?>
+-----
+name = $name;
+ }
+}
+
+?>
diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_no_readonly_doc.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_no_readonly_doc.php.inc
new file mode 100644
index 00000000000..f2047395390
--- /dev/null
+++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_no_readonly_doc.php.inc
@@ -0,0 +1,13 @@
+name = $name;
+ }
+}
diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_with_description.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_with_description.php.inc
new file mode 100644
index 00000000000..eb9dd784d86
--- /dev/null
+++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/Fixture/skip_with_description.php.inc
@@ -0,0 +1,16 @@
+name = $name;
+ }
+}
diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/RemoveUselessReadOnlyTagRectorTest.php b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/RemoveUselessReadOnlyTagRectorTest.php
new file mode 100644
index 00000000000..90b3a2dc676
--- /dev/null
+++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/RemoveUselessReadOnlyTagRectorTest.php
@@ -0,0 +1,28 @@
+doTestFile($filePath);
+ }
+
+ public static function provideData(): Iterator
+ {
+ return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
+ }
+
+ public function provideConfigFilePath(): string
+ {
+ return __DIR__ . '/config/configured_rule.php';
+ }
+}
diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/config/configured_rule.php b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/config/configured_rule.php
new file mode 100644
index 00000000000..862a435388c
--- /dev/null
+++ b/rules-tests/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector/config/configured_rule.php
@@ -0,0 +1,9 @@
+withRules([RemoveUselessReadOnlyTagRector::class]);
diff --git a/rules/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector.php b/rules/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector.php
new file mode 100644
index 00000000000..664a30ea752
--- /dev/null
+++ b/rules/DeadCode/Rector/Property/RemoveUselessReadOnlyTagRector.php
@@ -0,0 +1,108 @@
+name = $name;
+ }
+}
+CODE_SAMPLE
+
+ ,
+ <<<'CODE_SAMPLE'
+final class SomeClass
+{
+ private readonly string $name;
+
+ public function __construct(string $name)
+ {
+ $this->name = $name;
+ }
+}
+CODE_SAMPLE
+ ),
+ ]);
+ }
+
+ /**
+ * @return array>
+ */
+ public function getNodeTypes(): array
+ {
+ return [Class_::class, Property::class, Param::class];
+ }
+
+ /**
+ * @param Class_|Property|Param $node
+ */
+ public function refactor(Node $node): ?Node
+ {
+ // for param, only on property promotion
+ if ($node instanceof Param && $node->flags === 0) {
+ return null;
+ }
+
+ if (! $this->visibilityManipulator->isReadonly($node)) {
+ return null;
+ }
+
+ $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
+ $readonlyDoc = $phpDocInfo->getByName('readonly');
+ if (! $readonlyDoc instanceof PhpDocTagNode) {
+ return null;
+ }
+
+ if (! $readonlyDoc->value instanceof GenericTagValueNode) {
+ return null;
+ }
+
+ if ($readonlyDoc->value->value !== '') {
+ return null;
+ }
+
+ $phpDocInfo->removeByName('readonly');
+ $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($node);
+
+ return $node;
+ }
+}
diff --git a/src/Config/Level/DeadCodeLevel.php b/src/Config/Level/DeadCodeLevel.php
index 7e3ca367ec2..7c92251f1ee 100644
--- a/src/Config/Level/DeadCodeLevel.php
+++ b/src/Config/Level/DeadCodeLevel.php
@@ -39,6 +39,7 @@
use Rector\DeadCode\Rector\Node\RemoveNonExistingVarAnnotationRector;
use Rector\DeadCode\Rector\Plus\RemoveDeadZeroAndOneOperationRector;
use Rector\DeadCode\Rector\Property\RemoveUnusedPrivatePropertyRector;
+use Rector\DeadCode\Rector\Property\RemoveUselessReadOnlyTagRector;
use Rector\DeadCode\Rector\Property\RemoveUselessVarTagRector;
use Rector\DeadCode\Rector\PropertyProperty\RemoveNullPropertyInitializationRector;
use Rector\DeadCode\Rector\Return_\RemoveDeadConditionAboveReturnRector;
@@ -90,6 +91,7 @@ final class DeadCodeLevel
// docblock
RemoveUselessParamTagRector::class,
RemoveUselessReturnTagRector::class,
+ RemoveUselessReadOnlyTagRector::class,
RemoveNonExistingVarAnnotationRector::class,
RemoveUselessVarTagRector::class,
RemovePhpVersionIdCheckRector::class,