diff --git a/typo3/sysext/backend/Classes/Controller/SelectTreeController.php b/typo3/sysext/backend/Classes/Controller/SelectTreeController.php
index a0f6423a6b2b68ba22809a6a9768f5ebe4bfa5d5..eee0d931519ffe0d4421e0ca04953a0614534855 100644
--- a/typo3/sysext/backend/Classes/Controller/SelectTreeController.php
+++ b/typo3/sysext/backend/Classes/Controller/SelectTreeController.php
@@ -105,12 +105,12 @@ class SelectTreeController
 
         if ($formData['processedTca']['columns'][$fieldName]['config']['type'] === 'flex') {
             $treeData = $formData['processedTca']['columns'][$fieldName]['config']['ds']
-                ['sheets'][$flexFormPath[3]]['ROOT']['el'][$flexFormPath[5]]['config']['treeData'];
+                ['sheets'][$flexFormPath[3]]['ROOT']['el'][$flexFormPath[5]]['config']['items'];
         } else {
-            $treeData = $formData['processedTca']['columns'][$fieldName]['config']['treeData'];
+            $treeData = $formData['processedTca']['columns'][$fieldName]['config']['items'];
         }
 
-        $json = json_encode($treeData['items']);
+        $json = json_encode($treeData);
         $response->getBody()->write($json);
         return $response;
     }
diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php
index 58f001feb7c247a852958fa9d9b97a751bc64b16..f388e6f18401ae19f6badcc56c4a634b6044b732 100644
--- a/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php
+++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php
@@ -1358,8 +1358,9 @@ abstract class AbstractItemProvider
      * @param array $itemArray All item records for the select field
      * @param array $dynamicItemArray Item records from dynamic sources
      * @return array
+     * @todo: Check method usage, it's probably bogus in select context and was removed from select tree already.
      */
-    public function getStaticValues($itemArray, $dynamicItemArray)
+    protected function getStaticValues($itemArray, $dynamicItemArray)
     {
         $staticValues = [];
         foreach ($itemArray as $key => $item) {
diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaSelectTreeItems.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaSelectTreeItems.php
index 92fed04939be7fd3cee7e68f5a82ba10e153250a..ebd1b6321e6101aebcaadf7335f35cd4755d557f 100644
--- a/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaSelectTreeItems.php
+++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaSelectTreeItems.php
@@ -21,12 +21,20 @@ use TYPO3\CMS\Core\Tree\TableConfiguration\TreeDataProviderFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
- * Resolve select items, set processed item list in processedTca, sanitize and resolve database field
+ * Data provider for type=select + renderType=selectTree fields.
+ *
+ * Used in combination with SelectTreeElement to create the base HTML for trees,
+ * does a little bit of sanitation and preparation then.
+ *
+ * Used in combination with SelectTreeController to fetch the final tree list, this is
+ * triggered if $result['selectTreeCompileItems'] is set to true. This way the tree item
+ * calculation is only triggered if needed in this ajax context. Writes the prepared
+ * item array to ['config']['items'] in this case.
  */
 class TcaSelectTreeItems extends AbstractItemProvider implements FormDataProviderInterface
 {
     /**
-     * Resolve select items
+     * Sanitize config options and resolve select items if requested.
      *
      * @param array $result
      * @return array
@@ -50,7 +58,7 @@ class TcaSelectTreeItems extends AbstractItemProvider implements FormDataProvide
 
             // A couple of tree specific config parameters can be overwritten via page TS.
             // Pick those that influence the data fetching and write them into the config
-            // given to the tree data provider
+            // given to the tree data provider. This is additionally used in SelectTreeElement, so always do that.
             if (isset($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['config.']['treeConfig.'])) {
                 $pageTsConfig = $result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['config.']['treeConfig.'];
                 // If rootUid is set in pageTsConfig, use it
@@ -69,42 +77,93 @@ class TcaSelectTreeItems extends AbstractItemProvider implements FormDataProvide
             }
 
             if ($result['selectTreeCompileItems']) {
-                $fieldConfig['config']['items'] = $this->sanitizeItemArray($fieldConfig['config']['items'], $table, $fieldName);
-
-                $pageTsConfigAddItems = $this->addItemsFromPageTsConfig($result, $fieldName, []);
-                $fieldConfig['config']['items'] = $this->addItemsFromSpecial($result, $fieldName, $fieldConfig['config']['items']);
-                $fieldConfig['config']['items'] = $this->addItemsFromFolder($result, $fieldName, $fieldConfig['config']['items']);
-                $staticItems = $fieldConfig['config']['items'] + $pageTsConfigAddItems;
-
-                $fieldConfig['config']['items'] = $this->addItemsFromForeignTable($result, $fieldName, $fieldConfig['config']['items']);
-                $dynamicItems = array_diff_key($fieldConfig['config']['items'], $staticItems);
-
-                $fieldConfig['config']['items'] = $this->removeItemsByKeepItemsPageTsConfig($result, $fieldName, $fieldConfig['config']['items']);
-                $fieldConfig['config']['items'] = $pageTsConfigAddItems + $fieldConfig['config']['items'];
-                $fieldConfig['config']['items'] = $this->removeItemsByRemoveItemsPageTsConfig($result, $fieldName, $fieldConfig['config']['items']);
-
-                $fieldConfig['config']['items'] = $this->removeItemsByUserLanguageFieldRestriction($result, $fieldName, $fieldConfig['config']['items']);
-                $fieldConfig['config']['items'] = $this->removeItemsByUserAuthMode($result, $fieldName, $fieldConfig['config']['items']);
-                $fieldConfig['config']['items'] = $this->removeItemsByDoktypeUserRestriction($result, $fieldName, $fieldConfig['config']['items']);
-
-                // Resolve "itemsProcFunc"
-                if (!empty($fieldConfig['config']['itemsProcFunc'])) {
-                    $fieldConfig['config']['items'] = $this->resolveItemProcessorFunction($result, $fieldName, $fieldConfig['config']['items']);
-                    // itemsProcFunc must not be used anymore
-                    unset($fieldConfig['config']['itemsProcFunc']);
-                }
-
-                // Translate labels
-                $fieldConfig['config']['items'] = $this->translateLabels($result, $fieldConfig['config']['items'], $table, $fieldName);
-
-                $staticValues = $this->getStaticValues($fieldConfig['config']['items'], $dynamicItems);
+                // Prepare the list of currently selected nodes using RelationHandler
                 $result['databaseRow'][$fieldName] = $this->processDatabaseFieldValue($result['databaseRow'], $fieldName);
-                $result['databaseRow'][$fieldName] = $this->processSelectFieldValue($result, $fieldName, $staticValues);
-
-                // Keys may contain table names, so a numeric array is created
-                $fieldConfig['config']['items'] = array_values($fieldConfig['config']['items']);
+                $result['databaseRow'][$fieldName] = $this->processSelectFieldValue($result, $fieldName, []);
+
+                $finalItems = [];
+
+                // Prepare the list of "static" items if there are any.
+                // "static" and "dynamic" is separated since the tree code only copes with "real" existing foreign nodes,
+                // so this "static" stuff allows defining tree items that don't really exist in the tree.
+                $itemsFromTca = $this->sanitizeItemArray($fieldConfig['config']['items'], $table, $fieldName);
+                // List of additional items defined by page ts config "addItems"
+                $itemsFromPageTsConfig = $this->addItemsFromPageTsConfig($result, $fieldName, []);
+                if (!empty($itemsFromTca) || !empty($itemsFromPageTsConfig)) {
+                    // First apply "keepItems" to $itemsFromTca, this will restrict the tca item list to only
+                    // those items that are defined in page ts "keepItems" if given
+                    $itemsFromTca = $this->removeItemsByKeepItemsPageTsConfig($result, $fieldName, $itemsFromTca);
+                    // Then, merge the items from page ts "addItems" into item list, since "addItems" should
+                    // add additional items even if they are not in the "keepItems" list
+                    $staticItems = array_merge($itemsFromTca, $itemsFromPageTsConfig);
+                    // Now apply page ts config "removeItems", so this is *after* addItems, so "removeItems" could
+                    // possibly remove items again that were added via "addItems"
+                    $staticItems = $this->removeItemsByRemoveItemsPageTsConfig($result, $fieldName, $staticItems);
+                    // Now, apply user and access right restrictions to this item list
+                    $staticItems = $this->removeItemsByUserLanguageFieldRestriction($result, $fieldName, $staticItems);
+                    $staticItems = $this->removeItemsByUserAuthMode($result, $fieldName, $staticItems);
+                    $staticItems = $this->removeItemsByDoktypeUserRestriction($result, $fieldName, $staticItems);
+                    // Call itemsProcFunc if given. Note this function does *not* see the "dynamic" list of items
+                    if (!empty($fieldConfig['config']['itemsProcFunc'])) {
+                        $staticItems = $this->resolveItemProcessorFunction($result, $fieldName, $staticItems);
+                        // itemsProcFunc must not be used anymore
+                        unset($fieldConfig['config']['itemsProcFunc']);
+                    }
+                    // And translate any labels from the static list
+                    $staticItems = $this->translateLabels($result, $staticItems, $table, $fieldName);
+                    // Now compile the target items using the same array structure as the "dynamic" list below
+                    foreach ($staticItems as $item) {
+                        if ($item[1] === '--div--') {
+                            // Skip divs that may occur here for whatever reason
+                            continue;
+                        }
+                        $finalItems[] = [
+                            'identifier' => $item[1],
+                            'name' => $item[0],
+                            'icon' => $item[2] ?? '',
+                            'iconOverlay' => '',
+                            'depth' => 0,
+                            'hasChildren' => false,
+                            'selectable' => true,
+                            'checked' => in_array($item[1], $result['databaseRow'][$fieldName]),
+                        ];
+                    }
+                }
 
-                $fieldConfig['config']['treeData'] = $this->renderTree($result, $fieldConfig, $fieldName, $staticItems);
+                // Fetch the list of all possible "related" items (yuk!) and apply a similar processing as with the "static" list
+                $dynamicItems = $this->addItemsFromForeignTable($result, $fieldName, []);
+                $dynamicItems = $this->removeItemsByKeepItemsPageTsConfig($result, $fieldName, $dynamicItems);
+                $dynamicItems = $this->removeItemsByRemoveItemsPageTsConfig($result, $fieldName, $dynamicItems);
+                $dynamicItems = $this->removeItemsByUserLanguageFieldRestriction($result, $fieldName, $dynamicItems);
+                $dynamicItems = $this->removeItemsByUserAuthMode($result, $fieldName, $dynamicItems);
+                $dynamicItems = $this->removeItemsByDoktypeUserRestriction($result, $fieldName, $dynamicItems);
+                // Funnily, the only data needed for the tree code are the uids of the possible records (yuk!) - get them
+                $uidListOfAllDynamicItems = [];
+                foreach ($dynamicItems as $item) {
+                    if ((int)$item[1] > 0) {
+                        $uidListOfAllDynamicItems[] = (int)$item[1];
+                    }
+                }
+                // Now kick in this tree stuff
+                $treeDataProvider = TreeDataProviderFactory::getDataProvider(
+                    $fieldConfig['config'],
+                    $table,
+                    $fieldName,
+                    $result['databaseRow']
+                );
+                $treeDataProvider->setSelectedList(implode(',', $result['databaseRow'][$fieldName]));
+                // Basically the tree foo fetches all tree nodes again (aaargs), then verifies if
+                // a given rows uid is within this "list of allowed uids". It then creates an object
+                // tree representing the nested tree, just to collapse all that to a flat array again. Yay ...
+                $treeDataProvider->setItemWhiteList($uidListOfAllDynamicItems);
+                $treeDataProvider->initializeTreeData();
+                $treeRenderer = GeneralUtility::makeInstance(ExtJsArrayTreeRenderer::class);
+                $tree = GeneralUtility::makeInstance(TableConfigurationTree::class);
+                $tree->setDataProvider($treeDataProvider);
+                $tree->setNodeRenderer($treeRenderer);
+
+                // Merge tree nodes after calculated nodes from static items
+                $fieldConfig['config']['items'] = array_merge($finalItems, $tree->render());
             }
 
             $result['processedTca']['columns'][$fieldName] = $fieldConfig;
@@ -113,81 +172,6 @@ class TcaSelectTreeItems extends AbstractItemProvider implements FormDataProvide
         return $result;
     }
 
-    /**
-     * Renders the Ext JS tree.
-     *
-     * @param array $result The current result array.
-     * @param array $fieldConfig The configuration of the current field.
-     * @param string $fieldName The name of the current field.
-     * @param array $staticItems The static items from the field config.
-     * @return array The tree data configuration
-     */
-    protected function renderTree(array $result, array $fieldConfig, $fieldName, array $staticItems)
-    {
-        $allowedUids = [];
-        foreach ($fieldConfig['config']['items'] as $item) {
-            if ((int)$item[1] > 0) {
-                $allowedUids[] = $item[1];
-            }
-        }
-
-        $treeDataProvider = TreeDataProviderFactory::getDataProvider(
-            $fieldConfig['config'],
-            $result['tableName'],
-            $fieldName,
-            $result['databaseRow']
-        );
-        $treeDataProvider->setSelectedList(is_array($result['databaseRow'][$fieldName]) ? implode(',', $result['databaseRow'][$fieldName]) : $result['databaseRow'][$fieldName]);
-        $treeDataProvider->setItemWhiteList($allowedUids);
-        $treeDataProvider->initializeTreeData();
-
-        /** @var ExtJsArrayTreeRenderer $treeRenderer */
-        $treeRenderer = GeneralUtility::makeInstance(ExtJsArrayTreeRenderer::class);
-
-        /** @var TableConfigurationTree $tree */
-        $tree = GeneralUtility::makeInstance(TableConfigurationTree::class);
-        $tree->setDataProvider($treeDataProvider);
-        $tree->setNodeRenderer($treeRenderer);
-
-        $treeItems = $this->prepareAdditionalItems($staticItems, $result['databaseRow'][$fieldName]);
-        $treeItems[] = $tree->render();
-
-        $treeConfig = [
-            'items' => $treeItems,
-        ];
-
-        return $treeConfig;
-    }
-
-    /**
-     * Prepare the additional items that get prepended to the tree as leaves
-     *
-     * @param array $itemArray
-     * @param array $selectedNodes
-     * @return array
-     */
-    protected function prepareAdditionalItems(array $itemArray, array $selectedNodes)
-    {
-        $additionalItems = [];
-
-        foreach ($itemArray as $item) {
-            if ($item[1] === '--div--') {
-                continue;
-            }
-
-            $additionalItems[] = [
-                'uid' => $item[1],
-                'text' => $item[0],
-                'selectable' => true,
-                'leaf' => true,
-                'checked' => in_array($item[1], $selectedNodes),
-                'icon' => $item[2]
-            ];
-        }
-
-        return $additionalItems;
-    }
-
     /**
      * Determines whether the current field is a valid target for this DataProvider
      *
diff --git a/typo3/sysext/backend/Classes/Tree/Renderer/ExtJsJsonTreeRenderer.php b/typo3/sysext/backend/Classes/Tree/Renderer/ExtJsJsonTreeRenderer.php
index 4ff6365a8e3da3a9a47a0e7f49b8bb42fb63b661..12bd8622a239e031b2cdbddb2f05dc4c211f716e 100644
--- a/typo3/sysext/backend/Classes/Tree/Renderer/ExtJsJsonTreeRenderer.php
+++ b/typo3/sysext/backend/Classes/Tree/Renderer/ExtJsJsonTreeRenderer.php
@@ -13,7 +13,9 @@ namespace TYPO3\CMS\Backend\Tree\Renderer;
  *
  * The TYPO3 project - inspiring people to share!
  */
+use TYPO3\CMS\Backend\Tree\TreeNodeCollection;
 use TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider;
+use TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeNode;
 
 /**
  * Renderer for unordered lists
@@ -36,11 +38,14 @@ class ExtJsJsonTreeRenderer extends \TYPO3\CMS\Backend\Tree\Renderer\AbstractTre
      */
     public function renderNode(\TYPO3\CMS\Backend\Tree\TreeRepresentationNode $node, $recursive = true)
     {
-        $nodeArray = $this->getNodeArray($node);
+        $nodeArray = [];
+        $nodeArray[] = $this->getNodeArray($node);
         if ($recursive && $node->hasChildNodes()) {
             $this->recursionLevel++;
             $children = $this->renderNodeCollection($node->getChildNodes());
-            $nodeArray['children'] = $children;
+            foreach ($children as $child) {
+                $nodeArray[] = $child;
+            }
             $this->recursionLevel--;
         }
         return $nodeArray;
@@ -49,7 +54,7 @@ class ExtJsJsonTreeRenderer extends \TYPO3\CMS\Backend\Tree\Renderer\AbstractTre
     /**
      * Get node array
      *
-     * @param \TYPO3\CMS\Backend\Tree\TreeRepresentationNode $node
+     * @param \TYPO3\CMS\Backend\Tree\TreeRepresentationNode|DatabaseTreeNode $node
      * @return array
      */
     protected function getNodeArray(\TYPO3\CMS\Backend\Tree\TreeRepresentationNode $node)
@@ -64,27 +69,29 @@ class ExtJsJsonTreeRenderer extends \TYPO3\CMS\Backend\Tree\Renderer\AbstractTre
             $iconMarkup = $node->getIcon();
         }
         $nodeArray = [
-            'iconTag' => $iconMarkup,
-            'text' => htmlspecialchars($node->getLabel()),
-            'leaf' => !$node->hasChildNodes(),
-            'id' => htmlspecialchars($node->getId()),
-            'uid' => htmlspecialchars($node->getId()),
-
-            //svgtree
-            'icon' => $iconMarkup,
-            'overlayIcon' => $overlayIconMarkup,
             'identifier' => htmlspecialchars($node->getId()),
-            //no need for htmlspecialhars here as d3 is using 'textContent' property of the HTML DOM node
+            // No need for htmlspecialchars() here as d3 is using 'textContent' property of the HTML DOM node
             'name' => $node->getLabel(),
+            'icon' => $iconMarkup,
+            'overlayIcon' => $overlayIconMarkup,
+            'depth' => $this->recursionLevel,
+            'hasChildren' => (bool)$node->hasChildNodes(),
+            'selectable' => true,
         ];
-
+        if ($node instanceof DatabaseTreeNode) {
+            $nodeArray['checked'] = (bool)$node->getSelected();
+            if (!$node->getSelectable()) {
+                $nodeArray['checked'] = false;
+                $nodeArray['selectable'] = false;
+            }
+        }
         return $nodeArray;
     }
 
     /**
      * Renders a node collection recursive or just a single instance
      *
-     * @param \TYPO3\CMS\Backend\Tree\TreeNodeCollection $node
+     * @param \TYPO3\CMS\Backend\Tree\AbstractTree $tree
      * @param bool $recursive
      * @return string
      */
@@ -98,14 +105,24 @@ class ExtJsJsonTreeRenderer extends \TYPO3\CMS\Backend\Tree\Renderer\AbstractTre
     /**
      * Renders an tree recursive or just a single instance
      *
-     * @param \TYPO3\CMS\Backend\Tree\AbstractTree $node
+     * @param TreeNodeCollection $collection
      * @param bool $recursive
      * @return array
      */
-    public function renderNodeCollection(\TYPO3\CMS\Backend\Tree\TreeNodeCollection $collection, $recursive = true)
+    public function renderNodeCollection(TreeNodeCollection $collection, $recursive = true)
     {
+        $treeItems = [];
         foreach ($collection as $node) {
-            $treeItems[] = $this->renderNode($node, $recursive);
+            $allNodes = $this->renderNode($node, $recursive);
+            if ($allNodes[0]) {
+                $treeItems[] = $allNodes[0];
+            }
+            $nodeCount = count($allNodes);
+            if ($nodeCount > 1) {
+                for ($i = 1; $i < $nodeCount; $i++) {
+                    $treeItems[] = $allNodes[$i];
+                }
+            }
         }
         return $treeItems;
     }
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SelectTree.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SelectTree.js
index a20c7221faf1fc0a8de412deae899d49782a5277..e908dbc2f31dcae563868eecc3056d4224ac2cdc 100644
--- a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SelectTree.js
+++ b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SelectTree.js
@@ -59,7 +59,7 @@ define(['d3', 'TYPO3/CMS/Backend/FormEngine/Element/SvgTree'], function (d3, Svg
             nodeSelection
                 .selectAll('.tree-check use')
                 .attr('visibility', function (node) {
-                    var checked = Boolean(node.data.checked);
+                    var checked = Boolean(node.checked);
                     if (d3.select(this).classed('icon-checked') && checked) {
                         return 'visible';
                     } else if (d3.select(this).classed('icon-indeterminate') && node.indeterminate && !checked) {
@@ -85,7 +85,7 @@ define(['d3', 'TYPO3/CMS/Backend/FormEngine/Element/SvgTree'], function (d3, Svg
             //this can be simplified to single "use" element with changing href on click when we drop IE11 on WIN7 support
             var g = nodeSelection.filter(function (node) {
                     //do not render checkbox if node is not selectable
-                    return me.isNodeSelectable(node) || Boolean(node.data.checked);
+                    return me.isNodeSelectable(node) || Boolean(node.checked);
                 })
                 .append('g')
                 .attr('class', 'tree-check')
@@ -124,7 +124,7 @@ define(['d3', 'TYPO3/CMS/Backend/FormEngine/Element/SvgTree'], function (d3, Svg
         }
 
         return node.children.some(function (child) {
-            if (child.data.checked || child.indeterminate) {
+            if (child.checked || child.indeterminate) {
                 return true;
             }
         });
@@ -138,8 +138,9 @@ define(['d3', 'TYPO3/CMS/Backend/FormEngine/Element/SvgTree'], function (d3, Svg
     SelectTree.prototype.updateAncestorsIndetermineState = function (node) {
         var me = this;
         //foreach ancestor except node itself
-        node.ancestors().slice(1).forEach(function (n) {
-            n.indeterminate = (node.data.checked || node.indeterminate) ? true : me.hasCheckedOrIndeterminateChildren(n);
+        node.parents.forEach(function (index) {
+            var n = me.nodes[index];
+            n.indeterminate = (node.checked || node.indeterminate) ? true : me.hasCheckedOrIndeterminateChildren(n);
         });
     };
 
@@ -149,12 +150,12 @@ define(['d3', 'TYPO3/CMS/Backend/FormEngine/Element/SvgTree'], function (d3, Svg
      * It's done once after loading data. Later indeterminate state is updated just for the subset of nodes
      */
     SelectTree.prototype.loadDataAfter = function () {
-        this.rootNode.each(function (node) {
+        this.nodes.forEach(function (node) {
             node.indeterminate = false;
         });
-        this.calculateIndeterminate(this.rootNode);
+        this.calculateIndeterminate(this.nodes);
         // Initialise "value" attribute of input field after load and revalidate form engine fields
-        this.saveCheckboxes(this.rootNode);
+        this.saveCheckboxes(this.nodes);
         if (typeof TYPO3.FormEngine.Validation !== 'undefined' && typeof TYPO3.FormEngine.Validation.validate === 'function') {
             TYPO3.FormEngine.Validation.validate();
         }
@@ -172,7 +173,7 @@ define(['d3', 'TYPO3/CMS/Backend/FormEngine/Element/SvgTree'], function (d3, Svg
         }
 
         node.eachAfter(function (n) {
-            if ((n.data.checked || n.indeterminate) && n.parent) {
+            if ((n.checked || n.indeterminate) && n.parent) {
                 n.parent.indeterminate = true;
             }
         })
@@ -197,7 +198,7 @@ define(['d3', 'TYPO3/CMS/Backend/FormEngine/Element/SvgTree'], function (d3, Svg
         if (typeof this.settings.input !== 'undefined') {
             var selectedNodes = this.getSelectedNodes();
             this.settings.input.val(selectedNodes.map(function (d) {
-                    return d.data.identifier
+                    return d.identifier
             }));
         }
     };
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SvgTree.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SvgTree.js
index 93aab43337cd39960392454618c809e0359f6709..f20b71f5bb30e430a2d6b8760be2aedeca7df74e 100644
--- a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SvgTree.js
+++ b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/SvgTree.js
@@ -193,72 +193,32 @@ define(['jquery', 'd3'], function ($, d3) {
                     $container.parent().append('<p class="text-danger">' + TYPO3.lang['tcatree.msg_save_first'] + '</p>');
                     return;
                 }
-                if (Array.isArray(json)) {
-                    if (json.length > 1) {
-                        // If tree comes with multiple root nodes, add them to a new root
-                        var tmp = {
-                            checked: undefined,
-                            children: [],
-                            expandable: true,
-                            expanded: true,
-                            iconTag: null,
-                            id: '',
-                            identifier: 'root',
-                            leaf: false,
-                            name: '',
-                            overlayIcon: '',
-                            text: '',
-                            uid: ''
-                        };
-                        for (var i = 0; i < json.length; i++) {
-                            var n = json[i];
-                            if (typeof n.identifier === 'undefined') {
-                                n.identifier = n.uid;
-                            }
-                            if (typeof n.name === 'undefined') {
-                                n.name = n.text;
-                            }
-                            if (typeof n.expandable === 'undefined') {
-                                n.expandable = true;
-                            }
-                            if (typeof n.expanded === 'undefined') {
-                                n.expanded = true;
-                            }
-                            if (typeof n.icon !== 'undefined') {
-                                n.iconTag = n.icon;
-                            }
-                            tmp.children.push(n);
-                        }
-                        json = tmp;
-                    } else {
-                        json = json[0];
-                    }
-                }
-                var rootNode = d3.hierarchy(json);
-                d3.tree(rootNode);
-
-                rootNode.each(function (n) {
-                    n.open = (me.settings.expandUpToLevel !== null) ? n.depth < me.settings.expandUpToLevel : Boolean(n.expanded);
-                    n.hasChildren = (n.children || n._children) ? 1 : 0;
-                    n.parents = [];
-                    n._isDragged = false;
-                    if (n.parent) {
-                        var x = n;
-                        while (x && x.parent) {
-                            if (x.parent.data.identifier) {
-                                n.parents.push(x.parent.data.identifier);
+
+                var nodes = Array.isArray(json) ? json : [];
+                nodes = nodes.map(function (node, index) {
+                    node.open = (me.settings.expandUpToLevel !== null) ? node.depth < me.settings.expandUpToLevel : Boolean(node.expanded);
+                    node.parents = [];
+                    node._isDragged = false;
+                    if (node.depth > 0) {
+                        var currentDepth = node.depth;
+                        for (var i = index; i >= 0; i--) {
+                            var currentNode = nodes[i];
+                            if (currentNode.depth < currentDepth) {
+                                node.parents.push(i);
+                                currentDepth = currentNode.depth;
                             }
-                            x = x.parent;
                         }
                     }
-                    if (typeof n.data.checked == 'undefined') {
-                        n.data.checked = false;
-                        me.settings.unselectableElements.push(n.data.identifier);
+                    if (typeof node.checked == 'undefined') {
+                        node.checked = false;
+                        me.settings.unselectableElements.push(node.identifier);
                     }
                     //dispatch event
-                    me.dispatch.call('prepareLoadedNode', me, n);
+                    me.dispatch.call('prepareLoadedNode', me, node);
+                    return node;
                 });
-                me.rootNode = rootNode;
+
+                me.nodes = nodes;
                 me.dispatch.call('loadDataAfter', me);
                 me.prepareDataForVisibleNodes();
                 me.update();
@@ -274,17 +234,16 @@ define(['jquery', 'd3'], function ($, d3) {
             var me = this;
 
             var blacklist = {};
-            this.rootNode.eachBefore(function (node) {
+            this.nodes.map(function (node, index) {
                 if (!node.open) {
-                    blacklist[node.data.identifier] = true;
+                    blacklist[index] = true;
                 }
-
             });
 
-            this.data.nodes = this.rootNode.descendantsBefore().filter(function (node) {
-                return node.hidden != true && !node.parents.some(function (id) {
-                        return Boolean(blacklist[id]);
-                    });
+            this.data.nodes = this.nodes.filter(function (node) {
+                return node.hidden != true && !node.parents.some(function (index) {
+                    return Boolean(blacklist[index]);
+                });
             });
 
             var iconHashes = [];
@@ -294,33 +253,33 @@ define(['jquery', 'd3'], function ($, d3) {
                 //delete n.children;
                 n.x = n.depth * me.settings.indentWidth;
                 n.y = i * me.settings.nodeHeight;
-                if (n.parent) {
+                if (n.parents[0] !== undefined) {
                     me.data.links.push({
-                        source: n.parent,
+                        source: me.nodes[n.parents[0]],
                         target: n
                     });
                 }
-                if (!n.iconHash && me.settings.showIcons && n.data.icon) {
-                    n.iconHash = Math.abs(me.hashCode(n.data.icon));
+                if (!n.iconHash && me.settings.showIcons && n.icon) {
+                    n.iconHash = Math.abs(me.hashCode(n.icon));
                     if (iconHashes.indexOf(n.iconHash) === -1) {
                         iconHashes.push(n.iconHash);
                         me.data.icons.push({
                             identifier: n.iconHash,
-                            icon: n.data.icon
+                            icon: n.icon
                         });
                     }
-                    delete n.data.icon;
+                    delete n.icon;
                 }
-                if (!n.iconOverlayHash && me.settings.showIcons && n.data.overlayIcon) {
-                    n.iconOverlayHash = Math.abs(me.hashCode(n.data.overlayIcon));
+                if (!n.iconOverlayHash && me.settings.showIcons && n.overlayIcon) {
+                    n.iconOverlayHash = Math.abs(me.hashCode(n.overlayIcon));
                     if (iconHashes.indexOf(n.iconOverlayHash) === -1) {
                         iconHashes.push(n.iconOverlayHash);
                         me.data.icons.push({
                             identifier: n.iconOverlayHash,
-                            icon: n.data.overlayIcon
+                            icon: n.overlayIcon
                         });
                     }
-                    delete n.data.overlayIcon;
+                    delete n.overlayIcon;
                 }
             });
             this.svg.attr('height', this.data.nodes.length * this.settings.nodeHeight);
@@ -336,7 +295,7 @@ define(['jquery', 'd3'], function ($, d3) {
 
             var visibleNodes = this.data.nodes.slice(position, position + visibleRows);
             var nodes = this.nodesContainer.selectAll('.node').data(visibleNodes, function (d) {
-                return d.data.identifier;
+                return d.identifier;
             });
 
             // delete nodes without corresponding data
@@ -493,7 +452,7 @@ define(['jquery', 'd3'], function ($, d3) {
          * @returns {String}
          */
         getNodeLabel: function (node) {
-            return node.data.name;
+            return node.name;
         },
 
         /**
@@ -503,7 +462,7 @@ define(['jquery', 'd3'], function ($, d3) {
          * @returns {String}
          */
         getNodeClass: function (node) {
-            return 'node identifier-' + node.data.identifier;
+            return 'node identifier-' + node.identifier;
         },
 
         /**
@@ -513,7 +472,7 @@ define(['jquery', 'd3'], function ($, d3) {
          * @returns {String}
          */
         getNodeTitle: function (node) {
-            return 'uid=' + node.data.identifier;
+            return 'uid=' + node.identifier;
         },
 
         /**
@@ -611,7 +570,7 @@ define(['jquery', 'd3'], function ($, d3) {
             if (!this.isNodeSelectable(node)) {
                 return;
             }
-            var checked = node.data.checked;
+            var checked = node.checked;
             this.handleExclusiveNodeSelection(node);
 
             if (this.settings.validation && this.settings.validation.maxItems) {
@@ -620,7 +579,7 @@ define(['jquery', 'd3'], function ($, d3) {
                         return;
                     }
                 }
-            node.data.checked = !checked;
+            node.checked = !checked;
 
             this.dispatch.call('nodeSelectedAfter', this, node);
             this.update();
@@ -635,19 +594,19 @@ define(['jquery', 'd3'], function ($, d3) {
         handleExclusiveNodeSelection: function (node) {
             var exclusiveKeys = this.settings.exclusiveNodesIdentifiers.split(','),
                 me = this;
-            if (this.settings.exclusiveNodesIdentifiers.length && node.data.checked === false) {
-                if (exclusiveKeys.indexOf('' + node.data.identifier) > -1) {
+            if (this.settings.exclusiveNodesIdentifiers.length && node.checked === false) {
+                if (exclusiveKeys.indexOf('' + node.identifier) > -1) {
                     // this key is exclusive, so uncheck all others
                     this.rootNode.each(function (node) {
-                        if (node.data.checked === true) {
-                            node.data.checked = false;
+                        if (node.checked === true) {
+                            node.checked = false;
                             me.dispatch.call('nodeSelectedAfter', me, node);
                         }
                     });
                     this.exclusiveSelectedNode = node;
-                } else if (exclusiveKeys.indexOf('' + node.data.identifier) === -1 && this.exclusiveSelectedNode) {
+                } else if (exclusiveKeys.indexOf('' + node.identifier) === -1 && this.exclusiveSelectedNode) {
                     //current node is not exclusive, but other exclusive node is already selected
-                    this.exclusiveSelectedNode.data.checked = false;
+                    this.exclusiveSelectedNode.checked = false;
                     this.dispatch.call('nodeSelectedAfter', this, this.exclusiveSelectedNode);
                     this.exclusiveSelectedNode = null;
                 }
@@ -662,7 +621,7 @@ define(['jquery', 'd3'], function ($, d3) {
          * @returns {Boolean}
          */
         isNodeSelectable: function (node) {
-            return !this.settings.readOnlyMode && this.settings.unselectableElements.indexOf(node.data.identifier) == -1;
+            return !this.settings.readOnlyMode && this.settings.unselectableElements.indexOf(node.identifier) == -1;
         },
 
         /**
@@ -671,14 +630,9 @@ define(['jquery', 'd3'], function ($, d3) {
          * @returns {Node[]}
          */
         getSelectedNodes: function () {
-            var selectedNodes = [];
-
-            this.rootNode.each(function (node) {
-                if (node.data.checked) {
-                    selectedNodes.push(node)
-                }
+            return this.nodes.filter(function (node) {
+                return node.checked;
             });
-            return selectedNodes;
         },
 
         /**
@@ -743,7 +697,7 @@ define(['jquery', 'd3'], function ($, d3) {
          * Expand all nodes and refresh view
          */
         expandAll: function () {
-            this.rootNode.each(this.showChildren.bind(this));
+            this.nodes.forEach(this.showChildren.bind(this));
             this.prepareDataForVisibleNodes();
             this.update();
         },
@@ -752,7 +706,7 @@ define(['jquery', 'd3'], function ($, d3) {
          * Collapse all nodes recursively and refresh view
          */
         collapseAll: function () {
-            this.rootNode.each(this.hideChildren.bind(this));
+            this.nodes.forEach(this.hideChildren.bind(this));
             this.prepareDataForVisibleNodes();
             this.update();
         }
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/TreeToolbar.js b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/TreeToolbar.js
index d6ebb581f0c783a7da6e7b990c61d6f61ab720a6..f86d1a8bead965198c9c7047b178245f9d41f8aa 100644
--- a/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/TreeToolbar.js
+++ b/typo3/sysext/backend/Resources/Public/JavaScript/FormEngine/Element/TreeToolbar.js
@@ -146,10 +146,10 @@ define(['jquery', 'TYPO3/CMS/Backend/Icons', 'TYPO3/CMS/Backend/Tooltip', 'TYPO3
         var me = this,
             name = $(input).val();
 
-        this.tree.rootNode.open = false;
-        this.tree.rootNode.eachBefore(function (node, i) {
+        this.tree.nodes[0].open = false;
+        this.tree.nodes.forEach(function (node) {
             var regex = new RegExp(name, 'i');
-            if (regex.test(node.data.name)) {
+            if (regex.test(node.name)) {
                 me.showParents(node);
                 node.open = true;
                 node.hidden = false;
@@ -173,8 +173,8 @@ define(['jquery', 'TYPO3/CMS/Backend/Icons', 'TYPO3/CMS/Backend/Tooltip', 'TYPO3
         this._hideUncheckedState = !this._hideUncheckedState;
 
         if (this._hideUncheckedState) {
-            this.tree.rootNode.eachBefore(function (node, i) {
-                if (node.data.checked) {
+            this.tree.nodes.forEach(function (node) {
+                if (node.checked) {
                     me.showParents(node);
                     node.open = true;
                     node.hidden = false;
@@ -184,7 +184,7 @@ define(['jquery', 'TYPO3/CMS/Backend/Icons', 'TYPO3/CMS/Backend/Tooltip', 'TYPO3
                 }
             });
         } else {
-            this.tree.rootNode.eachBefore(function (node, i) {
+            this.tree.nodes.forEach(function (node) {
                 node.hidden = false;
             });
         }
@@ -199,14 +199,15 @@ define(['jquery', 'TYPO3/CMS/Backend/Icons', 'TYPO3/CMS/Backend/Tooltip', 'TYPO3
      * @returns {Boolean}
      */
     TreeToolbar.prototype.showParents = function (node) {
-        if (!node.parent) {
+        if (node.parents.length === 0) {
             return true;
         }
 
-        node.parent.hidden = false;
+        var parent = this.tree.nodes[node.parents[0]];
+        parent.hidden = false;
         //expand parent node
-        node.parent.open = true;
-        this.showParents(node.parent);
+        parent.open = true;
+        this.showParents(parent);
     };
 
     return TreeToolbar;
diff --git a/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaSelectTreeItemsTest.php b/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaSelectTreeItemsTest.php
index f3d66dd20a878e288bdb86b30bab3514ad1399dc..d9cb7486ce63d4b55abdc4496a42ed87346c024b 100644
--- a/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaSelectTreeItemsTest.php
+++ b/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaSelectTreeItemsTest.php
@@ -180,8 +180,8 @@ class TcaSelectTreeItemsTest extends UnitTestCase
 
         $expected = $input;
         $expected['databaseRow']['aField'] = ['1'];
-        $expected['processedTca']['columns']['aField']['config']['treeData'] = [
-            'items' => [['fake', 'tree', 'data']],
+        $expected['processedTca']['columns']['aField']['config']['items'] = [
+            'fake', 'tree', 'data',
         ];
         $this->assertEquals($expected, $this->subject->addData($input));
     }
@@ -207,6 +207,9 @@ class TcaSelectTreeItemsTest extends UnitTestCase
         /** @var  TableConfigurationTree|ObjectProphecy $treeDataProviderProphecy */
         $tableConfigurationTreeProphecy = $this->prophesize(TableConfigurationTree::class);
         GeneralUtility::addInstance(TableConfigurationTree::class, $tableConfigurationTreeProphecy->reveal());
+        $tableConfigurationTreeProphecy->render()->willReturn([]);
+        $tableConfigurationTreeProphecy->setDataProvider(Argument::cetera())->shouldBeCalled();
+        $tableConfigurationTreeProphecy->setNodeRenderer(Argument::cetera())->shouldBeCalled();
 
         $input = [
             'tableName' => 'aTable',
diff --git a/typo3/sysext/core/Classes/Tree/TableConfiguration/ExtJsArrayTreeRenderer.php b/typo3/sysext/core/Classes/Tree/TableConfiguration/ExtJsArrayTreeRenderer.php
index 326a495358ee5f5d231f2f9523a4d7e408a82257..e7eaa351cb5a4796eb23d3bcae969c045974fa96 100644
--- a/typo3/sysext/core/Classes/Tree/TableConfiguration/ExtJsArrayTreeRenderer.php
+++ b/typo3/sysext/core/Classes/Tree/TableConfiguration/ExtJsArrayTreeRenderer.php
@@ -19,27 +19,6 @@ namespace TYPO3\CMS\Core\Tree\TableConfiguration;
  */
 class ExtJsArrayTreeRenderer extends \TYPO3\CMS\Backend\Tree\Renderer\ExtJsJsonTreeRenderer
 {
-    /**
-     * Gets the node array. If the TCA configuration has defined items,
-     * they are added to rootlevel on top of the tree
-     *
-     * @param \TYPO3\CMS\Backend\Tree\TreeRepresentationNode|DatabaseTreeNode $node
-     * @return array
-     */
-    protected function getNodeArray(\TYPO3\CMS\Backend\Tree\TreeRepresentationNode $node)
-    {
-        $nodeArray = parent::getNodeArray($node);
-        $nodeArray = array_merge($nodeArray, [
-            'expanded' => $node->getExpanded(),
-            'expandable' => $node->hasChildNodes(),
-            'checked' => $node->getSelected()
-        ]);
-        if (!$node->getSelectable()) {
-            unset($nodeArray['checked']);
-        }
-        return $nodeArray;
-    }
-
     /**
      * Renders a node collection recursive or just a single instance
      *
@@ -50,7 +29,6 @@ class ExtJsArrayTreeRenderer extends \TYPO3\CMS\Backend\Tree\Renderer\ExtJsJsonT
     public function renderTree(\TYPO3\CMS\Backend\Tree\AbstractTree $tree, $recursive = true)
     {
         $this->recursionLevel = 0;
-        $children = $this->renderNode($tree->getRoot(), $recursive);
-        return $children;
+        return $this->renderNode($tree->getRoot(), $recursive);
     }
 }
diff --git a/typo3/sysext/core/Classes/Tree/TableConfiguration/TreeDataProviderFactory.php b/typo3/sysext/core/Classes/Tree/TableConfiguration/TreeDataProviderFactory.php
index c78ce41058a2764d5907df5ebe3488ddc8ec4da9..bf11ae3d5f105592a0a457160920f5d1edb5f717 100644
--- a/typo3/sysext/core/Classes/Tree/TableConfiguration/TreeDataProviderFactory.php
+++ b/typo3/sysext/core/Classes/Tree/TableConfiguration/TreeDataProviderFactory.php
@@ -26,7 +26,7 @@ class TreeDataProviderFactory
      * @param array $tcaConfiguration
      * @param $table
      * @param $field
-     * @param $currentValue
+     * @param array $currentValue The current database row, handing over 'uid' is enough
      * @return DatabaseTreeDataProvider
      * @throws \InvalidArgumentException
      */
@@ -45,7 +45,6 @@ class TreeDataProviderFactory
             $tcaConfiguration['internal_type'] = 'db';
         }
         if ($tcaConfiguration['internal_type'] === 'db') {
-            $unselectableUids = [];
             if ($dataProvider === null) {
                 $dataProvider = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::class);
             }
@@ -53,7 +52,9 @@ class TreeDataProviderFactory
                 $tableName = $tcaConfiguration['foreign_table'];
                 $dataProvider->setTableName($tableName);
                 if ($tableName == $table) {
-                    $unselectableUids[] = $currentValue['uid'];
+                    // The uid of the currently opened row can not be selected in a table relation to "self"
+                    $unselectableUids = [ $currentValue['uid'] ];
+                    $dataProvider->setItemUnselectableList($unselectableUids);
                 }
             } else {
                 throw new \InvalidArgumentException('TCA Tree configuration is invalid: "foreign_table" not set', 1288215888);
@@ -64,7 +65,6 @@ class TreeDataProviderFactory
                 $dataProvider->setLabelField($GLOBALS['TCA'][$tableName]['ctrl']['label']);
             }
             $dataProvider->setTreeId(md5($table . '|' . $field));
-            $dataProvider->setSelectedList($currentValue);
 
             $treeConfiguration = $tcaConfiguration['treeConfig'];
             if (isset($treeConfiguration['rootUid'])) {
@@ -90,7 +90,6 @@ class TreeDataProviderFactory
             } else {
                 throw new \InvalidArgumentException('TCA Tree configuration is invalid: neither "childrenField" nor "parentField" is set', 1288215889);
             }
-            $dataProvider->setItemUnselectableList($unselectableUids);
         } elseif ($tcaConfiguration['internal_type'] === 'file' && $dataProvider === null) {
             // @todo Not implemented yet
             throw new \InvalidArgumentException('TCA Tree configuration is invalid: tree for "internal_type=file" not implemented yet', 1288215891);