diff --git a/meta/lib/oeqa/selftest/cases/fitimage.py b/meta/lib/oeqa/selftest/cases/fitimage.py
index 2783e4e85c..6a0b0f82e9 100644
--- a/meta/lib/oeqa/selftest/cases/fitimage.py
+++ b/meta/lib/oeqa/selftest/cases/fitimage.py
@@ -432,6 +432,30 @@ class FitImageTestCase(OESelftestTestCase):
             mapped_name = dtb.replace('/', '_')
         return mapped_name
 
+    @staticmethod
+    def _get_test_dtb_files():
+        return (
+            ["test-ext.dtb", "test-overlay.dtbo"],
+            {"test-ext-alias.dtb": "test-ext.dtb"},
+        )
+
+    @staticmethod
+    def _get_external_dtb_files(devicetree_dir):
+        dtbs = []
+        aliases = {}
+
+        for name in sorted(os.listdir(devicetree_dir)):
+            if not name.endswith((".dtb", ".dtbo")):
+                continue
+
+            target = oe.fitimage.symlink_points_below(name, devicetree_dir)
+            if target:
+                aliases[name] = target
+            else:
+                dtbs.append(name)
+
+        return dtbs, aliases
+
     @staticmethod
     def _get_dtb_files(bb_vars):
         """Return a list of devicetree names
@@ -442,15 +466,22 @@ class FitImageTestCase(OESelftestTestCase):
         """
         kernel_devicetree = bb_vars.get('KERNEL_DEVICETREE')
         all_dtbs = []
-        dtb_symlinks = []
+        dtb_aliases = {}
+
         if kernel_devicetree:
             all_dtbs += [FitImageTestCase._apply_dtbvendored(bb_vars, dtb) for dtb in kernel_devicetree.split()]
-        # Support only the test recipe which provides 1 devicetree and 1 devicetree overlay
-        pref_prov_dtb = bb_vars.get('PREFERRED_PROVIDER_virtual/dtb')
-        if pref_prov_dtb == "test-dtbs-as-ext":
-            all_dtbs += ["test-ext.dtb", "test-overlay.dtbo"]
-            dtb_symlinks.append("test-ext-alias.dtb")
-        return (all_dtbs, dtb_symlinks)
+       
+        if bb_vars.get("PREFERRED_PROVIDER_virtual/dtb") == "test-dtbs-as-ext":
+            if bb_vars.get("_python_only_test"):
+                external_dtbs, external_aliases = FitImageTestCase._get_test_dtb_files()
+            else:
+                devicetree_dir = os.path.join(bb_vars["DEPLOY_DIR_IMAGE"], "devicetree")
+                external_dtbs, external_aliases = FitImageTestCase._get_external_dtb_files(devicetree_dir)
+
+            all_dtbs.extend(external_dtbs)
+            dtb_aliases.update(external_aliases)
+
+        return all_dtbs, dtb_aliases
 
     @staticmethod
     def _get_loadables(bb_vars):
@@ -473,13 +504,12 @@ class FitImageTestCase(OESelftestTestCase):
         configs = (bb_vars.get('FIT_CONFIGS') or "").split()
         kernels = FitImageTestCase._get_flag_values(bb_vars, 'FIT_CONFIG_KERNEL', configs)
         dtbs = FitImageTestCase._get_flag_values(bb_vars, 'FIT_CONFIG_DTB', configs)
-        _, dtb_symlinks = FitImageTestCase._get_dtb_files(bb_vars)
+        _, dtb_aliases = FitImageTestCase._get_dtb_files(bb_vars)
         extra_configs = []
         for conf in configs:
             dtb = dtbs[conf]
-            if dtb in dtb_symlinks:
-                # Symlinks of test-dtbs-as-ext point to the DTB without "-alias"
-                dtb = dtb.replace("-alias", "")
+            if dtb in dtb_aliases:
+                dtb = dtb_aliases[dtb]
             elif dtb:
                 dtb = FitImageTestCase._apply_dtbvendored(bb_vars, dtb)
             extra_configs.append((conf, kernels[conf] or "kernel-1", dtb))
@@ -976,10 +1006,10 @@ class KernelFitImageBase(FitImageTestCase):
                 if not dtb.endswith('.dtbo'):
                     its_field_check.append('kernel = "kernel-1";')
                 its_field_check.append('fdt = "fdt-%s";' % dtb)
-            for dtb in dtb_symlinks:
+
+            for dtb, target in dtb_symlinks.items():
                 its_field_check.append('kernel = "kernel-1";')
-                # Works only for tests were the symlink is with -alias suffix
-                its_field_check.append('fdt = "fdt-%s";' % dtb.replace('-alias', ''))
+                its_field_check.append('fdt = "fdt-%s";' % target)
 
             if initramfs_image and initramfs_image_bundle != "1":
                 its_field_check.append('ramdisk = "ramdisk-1";')
@@ -1076,11 +1106,10 @@ class KernelFitImageBase(FitImageTestCase):
                 req_sections[loadable]['Entry Point'] = entrypoint
         # Create a configuration section for each DTB
         if dtb_files:
-            for dtb in dtb_files + dtb_symlinks:
+            for dtb in dtb_files + list(dtb_symlinks):
                 conf_name = bb_vars['FIT_CONF_PREFIX'] + dtb
-                # Assume that DTBs with an "-alias" in its name are symlink DTBs created e.g. by the
-                # test-dtbs-as-ext test recipe. Make the configuration node pointing to the real DTB.
-                real_dtb = dtb.replace("-alias", "")
+                # Resolve DTB aliases using their explicit target mapping.
+                real_dtb = dtb_symlinks.get(dtb, dtb)
                 # dtb overlays do not refer to a kernel (yet?)
                 if dtb.endswith('.dtbo'):
                     req_sections[conf_name] = {
@@ -1146,7 +1175,7 @@ class KernelFitImageBase(FitImageTestCase):
         fit_hash_alg_len = FitImageTestCase.MKIMAGE_HASH_LENGTHS[fit_hash_alg]
         fit_sign_alg_len = FitImageTestCase.MKIMAGE_SIGNATURE_LENGTHS[fit_sign_alg]
         dtb_files, dtb_symlinks = FitImageTestCase._get_dtb_files(bb_vars)
-        all_dtb_names = set(dtb_files + dtb_symlinks)
+        all_dtb_names = set(dtb_files) | set(dtb_symlinks)
         # The public key is always injected into UBOOT_DTB_IMAGE (-K flag in
         # uboot-sign.bbclass concat_dtb).  For DTB-based configurations, the
         # same key is also injected into each per-configuration DTB, so either
@@ -1610,7 +1639,7 @@ class FitImagePyTests(KernelFitImageBase):
     def _test_fitimage_py(self, bb_vars_overrides=None):
         topdir = os.path.join(os.environ['BUILDDIR'])
         fitimage_its_path = os.path.join(topdir, self._testMethodName + '.its')
-
+        
         # Provide variables without calling bitbake
         bb_vars = {
             # image-fitimage.conf
@@ -1660,7 +1689,10 @@ class FitImagePyTests(KernelFitImageBase):
             # x86 kernels produce a setup.bin section; set to the file name to
             # enable it, or to "" / omit the key to suppress it.
             'KERNEL_SETUP_BIN': 'setup1.bin',
+            # ... existing entries ...
+            '_python_only_test': True,
         }
+
         if bb_vars_overrides:
             bb_vars.update(bb_vars_overrides)
             if logging.DEBUG >= self.logger.level:
@@ -1689,15 +1721,12 @@ class FitImagePyTests(KernelFitImageBase):
                 bb_vars.get('UBOOT_LOADADDRESS'), bb_vars.get('UBOOT_ENTRYPOINT'),
                 bb_vars.get('UBOOT_MKIMAGE_KERNEL_TYPE'))
 
-        dtb_files, dtb_symlinks = FitImageTestCase._get_dtb_files(bb_vars)
+        dtb_files, dtb_aliases = FitImageTestCase._get_dtb_files(bb_vars)
         for dtb in dtb_files:
             root_node.fitimage_emit_section_dtb(dtb, os.path.join("a-dir", dtb),
                 bb_vars.get("UBOOT_DTB_LOADADDRESS"), bb_vars.get("UBOOT_DTBO_LOADADDRESS"))
 
-        for dtb_symlink in dtb_symlinks:
-            # For test purposes, assume each symlink points to a DTB with the same basename minus "-alias"
-            # In this case, "test-ext-alias.dtb" -> "test-ext.dtb"
-            dtb_target = dtb_symlink.replace("-alias", "")
+        for dtb_symlink, dtb_target in dtb_aliases.items():
             root_node.fitimage_emit_section_dtb_alias(dtb_symlink, os.path.join("a-dir", dtb_target))
 
         if bb_vars.get('FIT_UBOOT_ENV'):
@@ -1910,6 +1939,7 @@ class UBootFitImageTests(FitImageTestCase):
             'UBOOT_SIGN_IMG_KEYNAME',
             'UBOOT_SIGN_KEYDIR',
             'UBOOT_SIGN_KEYNAME',
+            'EXTERNAL_KERNEL_DEVICETREE',
         }
         bb_vars = get_bb_vars(list(internal_used | set(additional_vars)), UBootFitImageTests.BOOTLOADER_RECIPE)
         self.logger.debug("bb_vars: %s" % pprint.pformat(bb_vars, indent=4))
