diff --git a/.github/workflows/osx-tests.yml b/.github/workflows/osx-tests.yml
index 13eab0aab97..6351a8e31fb 100644
--- a/.github/workflows/osx-tests.yml
+++ b/.github/workflows/osx-tests.yml
@@ -141,6 +141,7 @@ jobs:
             ~/Applications/CMake/3.15.7
             ~/Applications/CMake/3.19.7
             ~/Applications/CMake/3.23.5
+            ~/Applications/CMake/3.27.9
             ~/Applications/bazel/6.5.0
             ~/Applications/bazel/7.4.1
             ~/Applications/bazel/8.0.0
diff --git a/conan/tools/cmake/cmakedeps2/target_configuration.py b/conan/tools/cmake/cmakedeps2/target_configuration.py
index be3967ffdc0..dd3b7670a11 100644
--- a/conan/tools/cmake/cmakedeps2/target_configuration.py
+++ b/conan/tools/cmake/cmakedeps2/target_configuration.py
@@ -34,17 +34,21 @@ def filename(self):
         return f"{f}-Targets{build}-{config}.cmake"
 
     def _requires(self, info, components):
-        result = []
+        result = {}
         requires = info.parsed_requires()
         pkg_name = self._conanfile.ref.name
+        pkg_type = info.type
+        assert isinstance(pkg_type, PackageType), f"Pkg type {pkg_type} {type(pkg_type)}"
         transitive_reqs = self._cmakedeps.get_transitive_requires(self._conanfile)
+
         if not requires and not components:  # global cpp_info without components definition
             # require the pkgname::pkgname base (user defined) or INTERFACE base target
-            targets = []
             for d in transitive_reqs.values():
                 dep_target = self._cmakedeps.get_property("cmake_target_name", d)
-                targets.append(dep_target or f"{d.ref.name}::{d.ref.name}")
-            return targets
+                dep_target = dep_target or f"{d.ref.name}::{d.ref.name}"
+                link = not (pkg_type is PackageType.SHARED and d.package_type is PackageType.SHARED)
+                result[dep_target] = link
+            return result
 
         for required_pkg, required_comp in requires:
             if required_pkg is None:  # Points to a component of same package
@@ -53,7 +57,9 @@ def _requires(self, info, components):
                 dep_target = self._cmakedeps.get_property("cmake_target_name", self._conanfile,
                                                           required_comp)
                 dep_target = dep_target or f"{pkg_name}::{required_comp}"
-                result.append(dep_target)
+                link = not (pkg_type is PackageType.SHARED and
+                            dep_comp.package_type is PackageType.SHARED)
+                result[dep_target] = link
             else:  # Different package
                 try:
                     dep = transitive_reqs[required_pkg]
@@ -73,12 +79,15 @@ def _requires(self, info, components):
                         default_target = f"{required_pkg}::{required_comp}"
                     dep_target = self._cmakedeps.get_property("cmake_target_name", dep, comp)
                     dep_target = dep_target or default_target
-                    result.append(dep_target)
+                    link = not (pkg_type is PackageType.SHARED and
+                                dep_comp.package_type is PackageType.SHARED)
+                    result[dep_target] = link
         return result
 
     @property
     def _context(self):
         cpp_info = self._conanfile.cpp_info.deduce_full_cpp_info(self._conanfile)
+        assert isinstance(cpp_info.type, PackageType)
         pkg_name = self._conanfile.ref.name
         # fallback to consumer configuration if it doesn't have build_type
         config = self._conanfile.settings.get_safe("build_type", self._cmakedeps.configuration)
@@ -150,10 +159,10 @@ def _get_cmake_lib(self, info, components, pkg_folder, pkg_folder_var):
 
         includedirs = ";".join(self._path(i, pkg_folder, pkg_folder_var)
                                for i in info.includedirs) if info.includedirs else ""
-        requires = ";".join(self._requires(info, components))
+        requires = self._requires(info, components)
+        assert isinstance(requires, dict)
         defines = " ".join(info.defines)
         # TODO: Missing escaping?
-        # TODO: Missing link language
         # FIXME: Filter by lib traits!!!!!
         if not self._require.headers:  # If not depending on headers, paths and
             includedirs = defines = None
@@ -171,7 +180,7 @@ def _get_cmake_lib(self, info, components, pkg_folder, pkg_folder_var):
         if info.frameworks:
             ConanOutput(scope=str(self._conanfile)).warning("frameworks not supported yet in new CMakeDeps generator")
 
-        if info.libs:
+        if info.libs:  # TODO: to change to location
             if len(info.libs) != 1:
                 raise ConanException(f"New CMakeDeps only allows 1 lib per component:\n"
                                      f"{self._conanfile}: {info.libs}")
@@ -203,15 +212,14 @@ def _add_root_lib_target(self, libs, pkg_name, cpp_info):
         if libs and root_target_name not in libs:
             # Add a generic interface target for the package depending on the others
             if cpp_info.default_components is not None:
-                all_requires = []
+                all_requires = {}
                 for defaultc in cpp_info.default_components:
                     target_name = self._cmakedeps.get_property("cmake_target_name", self._conanfile,
                                                                defaultc)
                     comp_name = target_name or f"{pkg_name}::{defaultc}"
-                    all_requires.append(comp_name)
-                all_requires = ";".join(all_requires)
+                    all_requires[comp_name] = True  # It is an interface, full link
             else:
-                all_requires = ";".join(libs.keys())
+                all_requires = {k: True for k in libs.keys()}
             libs[root_target_name] = {"type": "INTERFACE",
                                       "requires": all_requires}
 
@@ -339,10 +347,29 @@ def _template(self):
         set_target_properties({{lib}} PROPERTIES IMPORTED_IMPLIB_{{config}}
                               "{{lib_info["link_location"]}}")
         {% endif %}
+
         {% if lib_info.get("requires") %}
-        set_target_properties({{lib}} PROPERTIES INTERFACE_LINK_LIBRARIES
-                              "{{config_wrapper(config, lib_info["requires"])}}")
+        # Information of transitive dependencies
+        {% for require_target, link in lib_info["requires"].items() %}
+        # Requirement {{require_target}} => Full link: {{link}}
+
+        {% if link %}
+        # set property allows to append, and lib_info[requires] will iterate
+        set_property(TARGET {{lib}} APPEND PROPERTY INTERFACE_LINK_LIBRARIES
+                     "{{config_wrapper(config, require_target)}}")
+        {% else %}
+        if(${CMAKE_VERSION} VERSION_LESS "3.27")
+            message(FATAL_ERROR "The 'CMakeToolchain' generator only works with CMake >= 3.27")
+        endif()
+        # If the headers trait is not there, this will do nothing
+        target_link_libraries({{lib}} INTERFACE
+                              $<COMPILE_ONLY:{{config_wrapper(config, require_target)}}> )
+        set_property(TARGET {{lib}} APPEND PROPERTY IMPORTED_LINK_DEPENDENT_LIBRARIES_{{config}}
+                     {{require_target}})
         {% endif %}
+        {% endfor %}
+        {% endif %}
+
         {% if lib_info.get("system_libs") %}
         target_link_libraries({{lib}} INTERFACE {{lib_info["system_libs"]}})
         {% endif %}
diff --git a/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_new.py b/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_new.py
index 4ee67b740ec..64a993e5e82 100644
--- a/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_new.py
+++ b/test/functional/toolchains/cmake/cmakedeps/test_cmakedeps_new.py
@@ -219,7 +219,7 @@ def test_libs_transitive(self, transitive_libraries, shared):
             assert "Conan: Target declared imported STATIC library 'engine::engine'" in c.out
 
     # if not using cmake >= 3.23 the intermediate gamelib_test linkage fail
-    @pytest.mark.tool("cmake", "3.23")
+    @pytest.mark.tool("cmake", "3.27")
     @pytest.mark.parametrize("shared", [False, True])
     def test_multilevel(self, shared):
         # TODO: make this shared fixtures in conftest for multi-level shared testing
@@ -338,8 +338,8 @@ def package_info(self):
         c.run(f"install app -c tools.cmake.cmakedeps:new={new_value} -g CMakeDeps")
         targets_cmake = c.load("app/pkg-Targets-release.cmake")
         assert "find_dependency(MyDep REQUIRED CONFIG)" in targets_cmake
-        assert 'set_target_properties(pkg::pkg PROPERTIES INTERFACE_LINK_LIBRARIES\n' \
-               '                      "$<$<CONFIG:RELEASE>:MyTargetDep>"' in targets_cmake
+        assert 'set_property(TARGET pkg::pkg APPEND PROPERTY INTERFACE_LINK_LIBRARIES\n' \
+               '             "$<$<CONFIG:RELEASE>:MyTargetDep>")' in targets_cmake
 
 
 class TestLibsLinkageTraits:
@@ -364,6 +364,7 @@ def test_linkage_shared_static(self):
         assert "engine/0.1: Hello World Release!"
         assert "game/0.1: Hello World Release!"
 
+    @pytest.mark.tool("cmake", "3.27")
     @pytest.mark.parametrize("shared", [False, True])
     def test_transitive_headers(self, shared):
         c = TestClient()
diff --git a/test/integration/graph/test_replace_requires.py b/test/integration/graph/test_replace_requires.py
index dbde54b949e..4b832ebac4a 100644
--- a/test/integration/graph/test_replace_requires.py
+++ b/test/integration/graph/test_replace_requires.py
@@ -451,8 +451,8 @@ class App(ConanFile):
         cmake = c.load("app/openssl-Targets-release.cmake")
         assert "find_dependency(ZLIB REQUIRED CONFIG)" in cmake
         assert "add_library(openssl::openssl STATIC IMPORTED)" in cmake
-        assert "set_target_properties(openssl::openssl PROPERTIES INTERFACE_LINK_LIBRARIES\n" \
-               '                      "$<$<CONFIG:RELEASE>:ZLIB::ZLIB>")' in cmake
+        assert "set_property(TARGET openssl::openssl APPEND PROPERTY INTERFACE_LINK_LIBRARIES\n" \
+               '             "$<$<CONFIG:RELEASE>:ZLIB::ZLIB>")' in cmake
 
     @pytest.mark.parametrize("diamond", [True, False])
     def test_openssl_components(self, diamond):
@@ -523,8 +523,8 @@ class App(ConanFile):
         cmake = c.load("app/openssl-Targets-release.cmake")
         assert "find_dependency(ZLIB REQUIRED CONFIG)" in cmake
         assert "add_library(openssl::crypto STATIC IMPORTED)" in cmake
-        assert "set_target_properties(openssl::crypto PROPERTIES INTERFACE_LINK_LIBRARIES\n" \
-               '                      "$<$<CONFIG:RELEASE>:ZLIB::ZLIB>")' in cmake
+        assert "set_property(TARGET openssl::crypto APPEND PROPERTY INTERFACE_LINK_LIBRARIES\n" \
+               '             "$<$<CONFIG:RELEASE>:ZLIB::ZLIB>")' in cmake
 
     @pytest.mark.parametrize("diamond", [True, False])
     @pytest.mark.parametrize("explicit_requires", [True, False])
@@ -601,8 +601,8 @@ class App(ConanFile):
         assert "find_dependency(ZLIB REQUIRED CONFIG)" in cmake
         assert "add_library(openssl::openssl STATIC IMPORTED)" in cmake
         # It should access the generic zlib-ng target
-        assert "set_target_properties(openssl::openssl PROPERTIES INTERFACE_LINK_LIBRARIES\n" \
-               '                      "$<$<CONFIG:RELEASE>:zlib-ng::zlib-ng>")' in cmake
+        assert "set_property(TARGET openssl::openssl APPEND PROPERTY INTERFACE_LINK_LIBRARIES\n" \
+               '             "$<$<CONFIG:RELEASE>:zlib-ng::zlib-ng>")' in cmake
 
     @pytest.mark.parametrize("diamond", [True, False])
     @pytest.mark.parametrize("package_requires", [False, True])
@@ -682,8 +682,8 @@ class App(ConanFile):
         assert "add_library(openssl::crypto STATIC IMPORTED)" in cmake
         if package_requires:
             # The generic package requirement uses the package name zlib-ng
-            assert "set_target_properties(openssl::crypto PROPERTIES INTERFACE_LINK_LIBRARIES\n" \
-                   '                      "$<$<CONFIG:RELEASE>:zlib-ng::zlib-ng>")' in cmake
+            assert "set_property(TARGET openssl::crypto APPEND PROPERTY INTERFACE_LINK_LIBRARIES\n" \
+                   '             "$<$<CONFIG:RELEASE>:zlib-ng::zlib-ng>")' in cmake
         else:
-            assert "set_target_properties(openssl::crypto PROPERTIES INTERFACE_LINK_LIBRARIES\n" \
-                   '                      "$<$<CONFIG:RELEASE>:ZLIB::ZLIB>")' in cmake
+            assert "set_property(TARGET openssl::crypto APPEND PROPERTY INTERFACE_LINK_LIBRARIES\n" \
+                   '             "$<$<CONFIG:RELEASE>:ZLIB::ZLIB>")' in cmake