diff --git a/typo3/sysext/core/Classes/Domain/RawRecord.php b/typo3/sysext/core/Classes/Domain/RawRecord.php
index 3f3287b5e61a27eddc256b288275e12c219277ab..c5b9ed02cdf67d124a9417cbce24c2ff79f63a8e 100644
--- a/typo3/sysext/core/Classes/Domain/RawRecord.php
+++ b/typo3/sysext/core/Classes/Domain/RawRecord.php
@@ -54,7 +54,7 @@ readonly class RawRecord implements RecordInterface
     public function getRecordType(): ?string
     {
         if (str_contains($this->type, '.')) {
-            return GeneralUtility::revExplode('.', $this->type, 2)[1];
+            return GeneralUtility::trimExplode('.', $this->type, true)[1] ?? null;
         }
         return null;
     }
@@ -62,7 +62,7 @@ readonly class RawRecord implements RecordInterface
     public function getMainType(): string
     {
         if (str_contains($this->type, '.')) {
-            return explode('.', $this->type)[0];
+            return explode('.', $this->type)[0] ?? '';
         }
         return $this->type;
     }
diff --git a/typo3/sysext/core/Classes/Domain/RecordFactory.php b/typo3/sysext/core/Classes/Domain/RecordFactory.php
index 554c034fde88b38d3f4892e17795dcaecdd6d90a..b3b49aca2e72c46fa393f69989afde0dd531009c 100644
--- a/typo3/sysext/core/Classes/Domain/RecordFactory.php
+++ b/typo3/sysext/core/Classes/Domain/RecordFactory.php
@@ -76,6 +76,13 @@ readonly class RecordFactory
         $subSchema = null;
         if ($schema->hasSubSchema($rawRecord->getRecordType() ?? '')) {
             $subSchema = $schema->getSubSchema($rawRecord->getRecordType());
+            // @todo Support of "subtypes" will most likely be deprecated in upcoming versions
+            if ($subSchema->getSubTypeDivisorField() !== null
+                && $rawRecord->has($subSchema->getSubTypeDivisorField()->getName())
+                && isset($subSchema->getSubSchemata()[$rawRecord->get($subSchema->getSubTypeDivisorField()->getName())])
+            ) {
+                $subSchema = $subSchema->getSubSchema($rawRecord->get($subSchema->getSubTypeDivisorField()->getName()));
+            }
         }
 
         // Only use the fields that are defined in the schema
@@ -103,6 +110,13 @@ readonly class RecordFactory
         $subSchema = null;
         if ($schema->hasSubSchema($rawRecord->getRecordType() ?? '')) {
             $subSchema = $schema->getSubSchema($rawRecord->getRecordType());
+            // @todo Support of "subtypes" will most likely be deprecated in upcoming versions
+            if ($subSchema->getSubTypeDivisorField() !== null
+                && $rawRecord->has($subSchema->getSubTypeDivisorField()->getName())
+                && isset($subSchema->getSubSchemata()[$rawRecord->get($subSchema->getSubTypeDivisorField()->getName())])
+            ) {
+                $subSchema = $subSchema->getSubSchema($rawRecord->get($subSchema->getSubTypeDivisorField()->getName()));
+            }
         }
 
         // Only use the fields that are defined in the schema
diff --git a/typo3/sysext/core/Classes/Schema/TcaSchema.php b/typo3/sysext/core/Classes/Schema/TcaSchema.php
index e30ae41f93da26843771e94a28b2d0dad25b0f65..8fa1207c6679e89bd56992d9929915b9ad995668 100644
--- a/typo3/sysext/core/Classes/Schema/TcaSchema.php
+++ b/typo3/sysext/core/Classes/Schema/TcaSchema.php
@@ -227,6 +227,17 @@ readonly class TcaSchema implements SchemaInterface
         return null;
     }
 
+    /**
+     * @internal "subtype" is not considered as API of TcaSchema since this feature will most likely be deprecated in upcoming versions
+     */
+    public function getSubTypeDivisorField(): ?FieldTypeInterface
+    {
+        if (isset($this->schemaConfiguration['subtype_value_field']) && isset($this->fields[$this->schemaConfiguration['subtype_value_field']])) {
+            return $this->fields[$this->schemaConfiguration['subtype_value_field']];
+        }
+        return null;
+    }
+
     /**
      * @return PassiveRelation[]
      */
diff --git a/typo3/sysext/core/Classes/Schema/TcaSchemaFactory.php b/typo3/sysext/core/Classes/Schema/TcaSchemaFactory.php
index 42e5b0b9423de997bc80fbc54e734e4aeafb6762..fcb91254383e0357a138f5f2f13c35d2b01934a7 100644
--- a/typo3/sysext/core/Classes/Schema/TcaSchemaFactory.php
+++ b/typo3/sysext/core/Classes/Schema/TcaSchemaFactory.php
@@ -211,13 +211,55 @@ class TcaSchemaFactory
 
                     $subSchemaFields[$fieldName] = $field;
                 }
-                $subSchema = new TcaSchema(
+
+                // @todo Support of "subtypes" will most likely be deprecated in upcoming versions
+                $subTypeSchemata = [];
+                if (isset($subSchemaDefinition['subtype_value_field'])
+                    && ($subTypeDivisorField = $subSchemaFields[$subSchemaDefinition['subtype_value_field']] ?? null) !== null
+                ) {
+                    // Add all the sub schema fields first. Afterwards extend this list based
+                    // on "subtypes_addlist" and reduce list based on "subtypes_excludelist".
+                    $subTypeFields = $subSchemaFields;
+                    $subTypes = array_filter(array_map(static fn(array $item) => $item['value'] ?? '', $subTypeDivisorField->getConfiguration()['items'] ?? []));
+                    foreach ($subTypes as $subType) {
+                        // Add fields based on "subtypes_addlist" configuration
+                        if ($subSchemaDefinition['subtypes_addlist'][$subType] ?? false) {
+                            $subTypeAddFields = GeneralUtility::trimExplode(',', (string)$subSchemaDefinition['subtypes_addlist'][$subType], true);
+                            foreach ($subTypeAddFields as $fieldName) {
+                                // Fetch the field from either the sub schema (taking columnsOverrides into account) or
+                                // fall back to the field based on the default configuration. In case field does not
+                                // exists, don't add it since it's not possible to add fields via subtypes, which have
+                                // not been defined beforehand.
+                                $field = $subSchemaFields[$fieldName] ?? $allFields[$fieldName] ?? null;
+                                if ($field === null) {
+                                    continue;
+                                }
+                                $subTypeFields[$fieldName] = $field;
+                            }
+                        }
+                        // Remove fields based on "subtypes_excludelist" configuration
+                        if ($subSchemaDefinition['subtypes_excludelist'][$subType] ?? false) {
+                            $subTypeExcludeFields = GeneralUtility::trimExplode(',', (string)$subSchemaDefinition['subtypes_excludelist'][$subType], true);
+                            foreach ($subTypeExcludeFields as $fieldName) {
+                                unset($subTypeFields[$fieldName]);
+                            }
+                        }
+
+                        $subTypeSchemata[$subType] = new TcaSchema(
+                            $schemaName . '.' . $subSchemaName . '.' . $subType,
+                            new FieldCollection($subTypeFields),
+                            array_replace_recursive($schemaConfiguration, $subSchemaDefinition)
+                        );
+                    }
+                }
+
+                $subSchemata[$subSchemaName] = new TcaSchema(
                     $schemaName . '.' . $subSchemaName,
                     new FieldCollection($subSchemaFields),
                     // Merge parts from the "types" section into the ctrl section of the main schema
-                    array_replace_recursive($schemaConfiguration, $subSchemaDefinition)
+                    array_replace_recursive($schemaConfiguration, $subSchemaDefinition),
+                    $subTypeSchemata !== [] ? new SchemaCollection($subTypeSchemata) : null
                 );
-                $subSchemata[$subSchemaName] = $subSchema;
             }
         }
         $schema = new TcaSchema(
diff --git a/typo3/sysext/core/Tests/Unit/Domain/RawRecordTest.php b/typo3/sysext/core/Tests/Unit/Domain/RawRecordTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0571563dbbbdfc4dad8ec77525771b6522f4aa50
--- /dev/null
+++ b/typo3/sysext/core/Tests/Unit/Domain/RawRecordTest.php
@@ -0,0 +1,66 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace TYPO3\CMS\Core\Tests\Unit\Domain;
+
+use PHPUnit\Framework\Attributes\DataProvider;
+use PHPUnit\Framework\Attributes\Test;
+use TYPO3\CMS\Core\Domain\RawRecord;
+use TYPO3\CMS\Core\Domain\Record\ComputedProperties;
+use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
+
+final class RawRecordTest extends UnitTestCase
+{
+    public static function getTypeReturnsExpectedValueDataProvider(): iterable
+    {
+        yield 'full type' => [
+            'tt_content',
+            'tt_content',
+            'tt_content',
+            null,
+        ];
+        yield 'record type' => [
+            'tt_content.list',
+            'tt_content.list',
+            'tt_content',
+            'list',
+        ];
+        yield 'sub type is ignored' => [
+            'tt_content.list.tx_blog_pi1',
+            'tt_content.list.tx_blog_pi1',
+            'tt_content',
+            'list',
+        ];
+        yield 'invalid config' => [
+            'tt_content....',
+            'tt_content....',
+            'tt_content',
+            null,
+        ];
+    }
+
+    #[DataProvider('getTypeReturnsExpectedValueDataProvider')]
+    #[Test]
+    public function getTypeReturnsExpectedParts(string $type, string $fullType, string $mainType, ?string $recordType): void
+    {
+        $record = new RawRecord(123, 456, [], $this->createMock(ComputedProperties::class), $type);
+
+        self::assertSame($fullType, $record->getFullType());
+        self::assertSame($mainType, $record->getMainType());
+        self::assertSame($recordType, $record->getRecordType());
+    }
+}
diff --git a/typo3/sysext/core/Tests/Unit/Schema/TcaSchemaFactoryTest.php b/typo3/sysext/core/Tests/Unit/Schema/TcaSchemaFactoryTest.php
index 69c61191f4bbfbb2b4eddfc3d128f2c9d186cba0..a19d56731eb4af5dd94705c5e6be33d40c76bcd7 100644
--- a/typo3/sysext/core/Tests/Unit/Schema/TcaSchemaFactoryTest.php
+++ b/typo3/sysext/core/Tests/Unit/Schema/TcaSchemaFactoryTest.php
@@ -20,6 +20,7 @@ namespace TYPO3\CMS\Core\Tests\Unit\Schema;
 use PHPUnit\Framework\Attributes\DataProvider;
 use PHPUnit\Framework\Attributes\Test;
 use TYPO3\CMS\Core\Cache\Frontend\PhpFrontend;
+use TYPO3\CMS\Core\Schema\Field\FieldTypeInterface;
 use TYPO3\CMS\Core\Schema\FieldTypeFactory;
 use TYPO3\CMS\Core\Schema\RelationMapBuilder;
 use TYPO3\CMS\Core\Schema\TcaSchemaFactory;
@@ -388,7 +389,7 @@ final class TcaSchemaFactoryTest extends UnitTestCase
     }
 
     #[Test]
-    public function subtypesInfoIsMergedWithMainSchemaInformation(): void
+    public function recordTypesInfoIsMergedWithMainSchemaInformation(): void
     {
         $cacheMock = $this->createMock(PhpFrontend::class);
         $cacheMock->method('has')->with(self::isType('string'))->willReturn(false);
@@ -424,4 +425,103 @@ final class TcaSchemaFactoryTest extends UnitTestCase
         self::assertSame('typeSpecificRenderer', $subSchema->getRawConfiguration()['previewRenderer']);
 
     }
+
+    public static function subtypesConfigurationIsAppliedToSubSchemaDataProvider(): iterable
+    {
+        yield 'No changes in subtype' => [
+            '',
+            '',
+            ['type', 'list_type', 'foo', 'bar'],
+        ];
+        yield 'Add fields' => [
+            'baz',
+            '',
+            ['type', 'list_type', 'foo', 'bar', 'baz'],
+        ];
+        yield 'Remove fields' => [
+            '',
+            'foo',
+            ['type', 'list_type', 'bar'],
+        ];
+        yield 'Add and remove fields' => [
+            'baz',
+            'foo',
+            ['type', 'list_type', 'bar', 'baz'],
+        ];
+        yield 'Unknown field is not added' => [
+            'unknown',
+            '',
+            ['type', 'list_type', 'foo', 'bar'],
+        ];
+    }
+
+    #[DataProvider('subtypesConfigurationIsAppliedToSubSchemaDataProvider')]
+    #[Test]
+    public function subtypesConfigurationIsAppliedToSubSchema(string $addList, string $excludeList, array $fields): void
+    {
+        $cacheMock = $this->createMock(PhpFrontend::class);
+        $cacheMock->method('has')->with(self::isType('string'))->willReturn(false);
+        $subject = new TcaSchemaFactory(
+            new RelationMapBuilder(),
+            new FieldTypeFactory(),
+            '',
+            $cacheMock
+        );
+        $subject->load([
+            'myTable' => [
+                'ctrl' => [
+                    'type' => 'type',
+                ],
+                'columns' => [
+                    'type' => [
+                        'config' => [
+                            'type' => 'select',
+                            'items' => [
+                                ['label' => 'list', 'value' => 'list'],
+                            ],
+                        ],
+                    ],
+                    'list_type' => [
+                        'config' => [
+                            'type' => 'select',
+                            'items' => [
+                                ['label' => 'Blog', 'value' => 'tx_blog_pi1'],
+                            ],
+                        ],
+                    ],
+                    'foo' => [
+                        'config' => [
+                            'type' => 'input',
+                        ],
+                    ],
+                    'bar' => [
+                        'config' => [
+                            'type' => 'input',
+                        ],
+                    ],
+                    'baz' => [
+                        'config' => [
+                            'type' => 'input',
+                        ],
+                    ],
+                ],
+                'types' => [
+                    'list' => [
+                        'showitem' => 'type,list_type,foo,bar',
+                        'subtype_value_field' => 'list_type',
+                        'subtypes_addlist' => [
+                            'tx_blog_pi1' => $addList,
+                        ],
+                        'subtypes_excludelist' => [
+                            'tx_blog_pi1' => $excludeList,
+                        ],
+                    ],
+                ],
+            ],
+        ]);
+
+        $schema = $subject->get('myTable.list');
+        self::assertTrue($schema->hasSubSchema('tx_blog_pi1'));
+        self::assertSame($fields, array_values(array_map(static fn(FieldTypeInterface $field) => $field->getName(), iterator_to_array($schema->getSubSchema('tx_blog_pi1')->getFields()->getIterator()))));
+    }
 }