Configurationtype

Use the snippet in the Magento 2 module creator.

Files

etc/Test_merged.xsd

<?xml version="1.0" ?>
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema">
	<xs:include schemaLocation="urn:magento:module:Mage2Gen_Module:etc/Test.xsd"/>
</xs:schema>

etc/Test.xsd

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified">
	<xs:element name="config">
		<xs:complexType>
			<xs:choice maxOccurs="unbounded">
				<xs:element name="Test" type="TestType" maxOccurs="unbounded" minOccurs="0"/>
			</xs:choice>
		</xs:complexType>
	</xs:element>
	<xs:complexType type="TestType">
		<xs:sequence>
			<xs:element name="Test" type="xs:string"/>
		</xs:sequence>
	</xs:complexType>
</xs:schema>

Config/Test/Converter.php

<?php
declare(strict_types=1);

namespace Mage2Gen\Module\Config\Test;

class Converter implements \Magento\Framework\Config\ConverterInterface
{

    /**
     * Convert dom node tree to array
     *
     * @param \DOMDocument $source
     * @return array
     */
    public function convert($source)
    {
        $output = [];
        $xpath = new \DOMXPath($source);
        $nodes = $xpath->evaluate('/config/Test');
        
        /** @var $node \DOMNode */
        foreach ($nodes as $node) {
            $nodeId = $node->attributes->getNamedItem('id');
        
            $data = [];
            $data['id'] = $nodeId;
            foreach ($node->childNodes as $childNode) {
                if ($childNode->nodeType != XML_ELEMENT_NODE) {
                    continue;
                }
        
                $data[$childNode->nodeName] = $childNode->nodeValue;
            }
            $output['Test'][$nodeId] = $data;
        }
        
        return $output;
    }
}

Config/Test/Reader.php

<?php
declare(strict_types=1);

namespace Mage2Gen\Module\Config\Test;

class Reader extends \Magento\Framework\Config\Reader\Filesystem
{

    protected $_idAttributes = [
        '/config/Test' => 'id',
    ];

    public function __construct(
        \Magento\Framework\Config\FileResolverInterface $fileResolver,
        Converter $converter,
        SchemaLocator $schemaLocator,
        \Magento\Framework\Config\ValidationStateInterface $validationState,
        $fileName = 'Test.xml',
        $idAttributes = [],
        $domDocumentClass = 'Magento\Framework\Config\Dom',
        $defaultScope = 'global'
    ) {
        parent::__construct(
            $fileResolver,
            $converter,
            $schemaLocator,
            $validationState,
            $fileName,
            $idAttributes,
            $domDocumentClass,
            $defaultScope
        );
    }
}

Config/Test/SchemaLocator.php

<?php
declare(strict_types=1);

namespace Mage2Gen\Module\Config\Test;

use Magento\Framework\Module\Dir;

class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface
{

    protected $_schema = null;
    protected $_perFileSchema = null;

    /**
     * @param \Magento\Framework\Module\Dir\Reader $moduleReader
     */
    public function __construct(
        \Magento\Framework\Module\Dir\Reader $moduleReader
    ) {
        $etcDir = $moduleReader->getModuleDir(Dir::MODULE_ETC_DIR, 'Mage2Gen_Module');
        $this->_schema = $etcDir . '/Test_merged.xsd';
        $this->_perFileSchema = $etcDir . '/Test.xsd';
    }

    /**
     * Get path to merged config schema
     *
     * @return string|null
     */
    public function getSchema()
    {
        return $this->_schema;
    }

    /**
     * Get path to pre file validation schema
     *
     * @return string|null
     */
    public function getPerFileSchema()
    {
        return $this->_perFileSchema;
    }
}