diff --git a/Sources/Build/BuildDescription/ProductBuildDescription.swift b/Sources/Build/BuildDescription/ProductBuildDescription.swift
index 4d11412723d..5f1c65a667b 100644
--- a/Sources/Build/BuildDescription/ProductBuildDescription.swift
+++ b/Sources/Build/BuildDescription/ProductBuildDescription.swift
@@ -286,7 +286,8 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
             // When deploying to macOS prior to macOS 12, add an rpath to the
             // back-deployed concurrency libraries.
             if useStdlibRpath, triple.isMacOSX {
-                let macOSSupportedPlatform = self.package.platforms.getDerived(for: .macOS, usingXCTest: product.isLinkingXCTest)
+                let macOSSupportedPlatform = self.package.getSupportedPlatform(for: .macOS, usingXCTest: product.isLinkingXCTest)
+
                 if macOSSupportedPlatform.version.major < 12 {
                     let backDeployedStdlib = try buildParameters.toolchain.macosSwiftStdlib
                         .parentDirectory
diff --git a/Sources/Build/BuildPlan/BuildPlan+Test.swift b/Sources/Build/BuildPlan/BuildPlan+Test.swift
index 0b5427d134f..6c4bed6a3ef 100644
--- a/Sources/Build/BuildPlan/BuildPlan+Test.swift
+++ b/Sources/Build/BuildPlan/BuildPlan+Test.swift
@@ -87,7 +87,8 @@ extension BuildPlan {
                     target: discoveryTarget,
                     dependencies: testProduct.targets.map { .target($0, conditions: []) },
                     defaultLocalization: testProduct.defaultLocalization,
-                    platforms: testProduct.platforms
+                    supportedPlatforms: testProduct.supportedPlatforms,
+                    platformVersionProvider: testProduct.platformVersionProvider
                 )
                 let discoveryTargetBuildDescription = try SwiftTargetBuildDescription(
                     package: package,
@@ -124,7 +125,8 @@ extension BuildPlan {
                     target: entryPointTarget,
                     dependencies: testProduct.targets.map { .target($0, conditions: []) } + resolvedTargetDependencies,
                     defaultLocalization: testProduct.defaultLocalization,
-                    platforms: testProduct.platforms
+                    supportedPlatforms: testProduct.supportedPlatforms,
+                    platformVersionProvider: testProduct.platformVersionProvider
                 )
                 return try SwiftTargetBuildDescription(
                     package: package,
@@ -166,7 +168,8 @@ extension BuildPlan {
                             target: entryPointTarget,
                             dependencies: entryPointResolvedTarget.dependencies + resolvedTargetDependencies,
                             defaultLocalization: testProduct.defaultLocalization,
-                            platforms: testProduct.platforms
+                            supportedPlatforms: testProduct.supportedPlatforms,
+                            platformVersionProvider: testProduct.platformVersionProvider
                         )
                         let entryPointTargetBuildDescription = try SwiftTargetBuildDescription(
                             package: package,
diff --git a/Sources/Build/BuildPlan/BuildPlan.swift b/Sources/Build/BuildPlan/BuildPlan.swift
index 92c888ff178..849f32f8ab5 100644
--- a/Sources/Build/BuildPlan/BuildPlan.swift
+++ b/Sources/Build/BuildPlan/BuildPlan.swift
@@ -134,7 +134,7 @@ extension BuildParameters {
         // Compute the triple string for Darwin platform using the platform version.
         if self.triple.isDarwin() {
             let platform = buildEnvironment.platform
-            let supportedPlatform = target.platforms.getDerived(for: platform, usingXCTest: target.type == .test)
+            let supportedPlatform = target.getSupportedPlatform(for: platform, usingXCTest: target.type == .test)
             args += [self.triple.tripleString(forPlatformVersion: supportedPlatform.version.versionString)]
         } else {
             args += [self.triple.tripleString]
@@ -455,8 +455,8 @@ public class BuildPlan: SPMBuildCore.BuildPlan {
     ) throws {
         // Supported platforms are defined at the package level.
         // This will need to become a bit complicated once we have target-level or product-level platform support.
-        let productPlatform = product.platforms.getDerived(for: .macOS, usingXCTest: product.isLinkingXCTest)
-        let targetPlatform = target.platforms.getDerived(for: .macOS, usingXCTest: target.type == .test)
+        let productPlatform = product.getSupportedPlatform(for: .macOS, usingXCTest: product.isLinkingXCTest)
+        let targetPlatform = target.getSupportedPlatform(for: .macOS, usingXCTest: target.type == .test)
 
         // Check if the version requirement is satisfied.
         //
diff --git a/Sources/PackageGraph/CMakeLists.txt b/Sources/PackageGraph/CMakeLists.txt
index 30dce2f22a3..3e432482f01 100644
--- a/Sources/PackageGraph/CMakeLists.txt
+++ b/Sources/PackageGraph/CMakeLists.txt
@@ -32,6 +32,7 @@ add_library(PackageGraph
   Resolution/DependencyResolverBinding.swift
   Resolution/DependencyResolverDelegate.swift
   Resolution/DependencyResolverError.swift
+  Resolution/PlatformVersionProvider.swift
   Resolution/ResolvedPackage.swift
   Resolution/ResolvedProduct.swift
   Resolution/ResolvedTarget.swift
diff --git a/Sources/PackageGraph/PackageGraph+Loading.swift b/Sources/PackageGraph/PackageGraph+Loading.swift
index 5fe6b21ec30..d3f7cf4859b 100644
--- a/Sources/PackageGraph/PackageGraph+Loading.swift
+++ b/Sources/PackageGraph/PackageGraph+Loading.swift
@@ -145,6 +145,13 @@ extension PackageGraph {
             }
         }
 
+        let platformVersionProvider: PlatformVersionProvider
+        if let customXCTestMinimumDeploymentTargets {
+            platformVersionProvider = .init(implementation: .customXCTestMinimumDeploymentTargets(customXCTestMinimumDeploymentTargets))
+        } else {
+            platformVersionProvider = .init(implementation: .minimumDeploymentTargetDefault)
+        }
+
         // Resolve dependencies and create resolved packages.
         let resolvedPackages = try createResolvedPackages(
             nodes: allNodes,
@@ -153,13 +160,7 @@ extension PackageGraph {
             rootManifests: root.manifests,
             unsafeAllowedPackages: unsafeAllowedPackages,
             platformRegistry: customPlatformsRegistry ?? .default,
-            derivedXCTestPlatformProvider: { declared in
-                if let customXCTestMinimumDeploymentTargets {
-                    return customXCTestMinimumDeploymentTargets[declared]
-                } else {
-                    return MinimumDeploymentTarget.default.computeXCTestMinimumDeploymentTarget(for: declared)
-                }
-            },
+            platformVersionProvider: platformVersionProvider,
             fileSystem: fileSystem,
             observabilityScope: observabilityScope
         )
@@ -240,7 +241,7 @@ private func createResolvedPackages(
     rootManifests: [PackageIdentity: Manifest],
     unsafeAllowedPackages: Set<PackageReference>,
     platformRegistry: PlatformRegistry,
-    derivedXCTestPlatformProvider: @escaping (_ declared: PackageModel.Platform) -> PlatformVersion?,
+    platformVersionProvider: PlatformVersionProvider,
     fileSystem: FileSystem,
     observabilityScope: ObservabilityScope
 ) throws -> [ResolvedPackage] {
@@ -257,7 +258,8 @@ private func createResolvedPackages(
             package,
             productFilter: node.productFilter,
             isAllowedToVendUnsafeProducts: isAllowedToVendUnsafeProducts,
-            allowedToOverride: allowedToOverride
+            allowedToOverride: allowedToOverride,
+            platformVersionProvider: platformVersionProvider
         )
     }
 
@@ -361,14 +363,19 @@ private func createResolvedPackages(
 
         packageBuilder.defaultLocalization = package.manifest.defaultLocalization
 
-        packageBuilder.platforms = computePlatforms(
+        packageBuilder.supportedPlatforms = computePlatforms(
             package: package,
-            platformRegistry: platformRegistry,
-            derivedXCTestPlatformProvider: derivedXCTestPlatformProvider
+            platformRegistry: platformRegistry
         )
 
         // Create target builders for each target in the package.
-        let targetBuilders = package.targets.map{ ResolvedTargetBuilder(target: $0, observabilityScope: packageObservabilityScope) }
+        let targetBuilders = package.targets.map {
+            ResolvedTargetBuilder(
+                target: $0,
+                observabilityScope: packageObservabilityScope,
+                platformVersionProvider: platformVersionProvider
+            )
+        }
         packageBuilder.targets = targetBuilders
 
         // Establish dependencies between the targets. A target can only depend on another target present in the same package.
@@ -386,7 +393,7 @@ private func createResolvedPackages(
                 }
             }
             targetBuilder.defaultLocalization = packageBuilder.defaultLocalization
-            targetBuilder.platforms = packageBuilder.platforms
+            targetBuilder.supportedPlatforms = packageBuilder.supportedPlatforms
         }
 
         // Create product builders for each product in the package. A product can only contain a target present in the same package.
@@ -743,10 +750,8 @@ private class DuplicateProductsChecker {
 
 private func computePlatforms(
     package: Package,
-    platformRegistry: PlatformRegistry,
-    derivedXCTestPlatformProvider: @escaping (_ declared: PackageModel.Platform) -> PlatformVersion?
-) -> SupportedPlatforms {
-
+    platformRegistry: PlatformRegistry
+) -> [SupportedPlatform] {
     // the supported platforms as declared in the manifest
     let declaredPlatforms: [SupportedPlatform] = package.manifest.platforms.map { platform in
         let declaredPlatform = platformRegistry.platformByName[platform.platformName]
@@ -758,10 +763,7 @@ private func computePlatforms(
         )
     }
 
-    return SupportedPlatforms(
-        declared: declaredPlatforms.sorted(by: { $0.platform.name < $1.platform.name }),
-        derivedXCTestPlatformProvider: derivedXCTestPlatformProvider
-    )
+    return declaredPlatforms.sorted(by: { $0.platform.name < $1.platform.name })
 }
 
 // Track and override module aliases specified for targets in a package graph
@@ -888,11 +890,14 @@ private final class ResolvedTargetBuilder: ResolvedBuilder<ResolvedTarget> {
     var defaultLocalization: String? = nil
 
     /// The platforms supported by this package.
-    var platforms: SupportedPlatforms = .init(declared: [], derivedXCTestPlatformProvider: .none)
+    var supportedPlatforms: [SupportedPlatform] = []
+
+    let platformVersionProvider: PlatformVersionProvider
 
     init(
         target: Target,
-        observabilityScope: ObservabilityScope
+        observabilityScope: ObservabilityScope,
+        platformVersionProvider: PlatformVersionProvider
     ) {
         self.target = target
         self.diagnosticsEmitter = observabilityScope.makeDiagnosticsEmitter() {
@@ -900,6 +905,7 @@ private final class ResolvedTargetBuilder: ResolvedBuilder<ResolvedTarget> {
             metadata.targetName = target.name
             return metadata
         }
+        self.platformVersionProvider = platformVersionProvider
     }
 
     func diagnoseInvalidUseOfUnsafeFlags(_ product: ResolvedProduct) throws {
@@ -934,7 +940,8 @@ private final class ResolvedTargetBuilder: ResolvedBuilder<ResolvedTarget> {
             target: self.target,
             dependencies: dependencies,
             defaultLocalization: self.defaultLocalization,
-            platforms: self.platforms
+            supportedPlatforms: self.supportedPlatforms,
+            platformVersionProvider: self.platformVersionProvider
         )
     }
 }
@@ -983,27 +990,37 @@ private final class ResolvedPackageBuilder: ResolvedBuilder<ResolvedPackage> {
     var defaultLocalization: String? = nil
 
     /// The platforms supported by this package.
-    var platforms: SupportedPlatforms = .init(declared: [], derivedXCTestPlatformProvider: .none)
+    var supportedPlatforms: [SupportedPlatform] = []
 
     /// If the given package's source is a registry release, this provides additional metadata and signature information.
     var registryMetadata: RegistryReleaseMetadata?
 
-    init(_ package: Package, productFilter: ProductFilter, isAllowedToVendUnsafeProducts: Bool, allowedToOverride: Bool) {
+    let platformVersionProvider: PlatformVersionProvider
+
+    init(
+        _ package: Package,
+        productFilter: ProductFilter,
+        isAllowedToVendUnsafeProducts: Bool,
+        allowedToOverride: Bool,
+        platformVersionProvider: PlatformVersionProvider
+    ) {
         self.package = package
         self.productFilter = productFilter
         self.isAllowedToVendUnsafeProducts = isAllowedToVendUnsafeProducts
         self.allowedToOverride = allowedToOverride
+        self.platformVersionProvider = platformVersionProvider
     }
 
     override func constructImpl() throws -> ResolvedPackage {
         return ResolvedPackage(
             package: self.package,
             defaultLocalization: self.defaultLocalization,
-            platforms: self.platforms,
+            supportedPlatforms: self.supportedPlatforms,
             dependencies: try self.dependencies.map{ try $0.construct() },
             targets: try self.targets.map{ try $0.construct() },
             products: try self.products.map{ try $0.construct() },
-            registryMetadata: self.registryMetadata
+            registryMetadata: self.registryMetadata,
+            platformVersionProvider: self.platformVersionProvider
         )
     }
 }
diff --git a/Sources/PackageGraph/Resolution/PlatformVersionProvider.swift b/Sources/PackageGraph/Resolution/PlatformVersionProvider.swift
new file mode 100644
index 00000000000..d35da0e0238
--- /dev/null
+++ b/Sources/PackageGraph/Resolution/PlatformVersionProvider.swift
@@ -0,0 +1,114 @@
+//===----------------------------------------------------------------------===//
+//
+// This source file is part of the Swift open source project
+//
+// Copyright (c) 2014-2023 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See http://swift.org/LICENSE.txt for license information
+// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+import struct PackageModel.MinimumDeploymentTarget
+import struct PackageModel.Platform
+import struct PackageModel.PlatformVersion
+import struct PackageModel.SupportedPlatform
+
+/// Merging two sets of supported platforms, preferring the max constraint
+func merge(into partial: inout [SupportedPlatform], platforms: [SupportedPlatform]) {
+    for platformSupport in platforms {
+        if let existing = partial.firstIndex(where: { $0.platform == platformSupport.platform }) {
+            if partial[existing].version < platformSupport.version {
+                partial.remove(at: existing)
+                partial.append(platformSupport)
+            }
+        } else {
+            partial.append(platformSupport)
+        }
+    }
+}
+
+public struct PlatformVersionProvider: Hashable {
+    public enum Implementation: Hashable {
+        case mergingFromTargets([ResolvedTarget])
+        case customXCTestMinimumDeploymentTargets([PackageModel.Platform: PlatformVersion])
+        case minimumDeploymentTargetDefault
+    }
+
+    private let implementation: Implementation
+
+    public init(implementation: Implementation) {
+        self.implementation = implementation
+    }
+
+    func derivedXCTestPlatformProvider(_ declared: PackageModel.Platform) -> PlatformVersion? {
+        switch self.implementation {
+        case .mergingFromTargets(let targets):
+            let platforms = targets.reduce(into: [SupportedPlatform]()) { partial, item in
+                merge(
+                    into: &partial,
+                    platforms: [item.getSupportedPlatform(for: declared, usingXCTest: item.type == .test)]
+                )
+            }
+            return platforms.first!.version
+
+        case .customXCTestMinimumDeploymentTargets(let customXCTestMinimumDeploymentTargets):
+            return customXCTestMinimumDeploymentTargets[declared]
+
+        case .minimumDeploymentTargetDefault:
+            return MinimumDeploymentTarget.default.computeXCTestMinimumDeploymentTarget(for: declared)
+        }
+    }
+
+    /// Returns the supported platform instance for the given platform.
+    func getDerived(declared: [SupportedPlatform], for platform: Platform, usingXCTest: Bool) -> SupportedPlatform {
+        // derived platform based on known minimum deployment target logic
+        if let declaredPlatform = declared.first(where: { $0.platform == platform }) {
+            var version = declaredPlatform.version
+
+            if usingXCTest,
+               let xcTestMinimumDeploymentTarget = self.derivedXCTestPlatformProvider(platform),
+               version < xcTestMinimumDeploymentTarget
+            {
+                version = xcTestMinimumDeploymentTarget
+            }
+
+            // If the declared version is smaller than the oldest supported one, we raise the derived version to that.
+            if version < platform.oldestSupportedVersion {
+                version = platform.oldestSupportedVersion
+            }
+
+            return SupportedPlatform(
+                platform: declaredPlatform.platform,
+                version: version,
+                options: declaredPlatform.options
+            )
+        } else {
+            let minimumSupportedVersion: PlatformVersion
+            if usingXCTest,
+               let xcTestMinimumDeploymentTarget = self.derivedXCTestPlatformProvider(platform),
+               xcTestMinimumDeploymentTarget > platform.oldestSupportedVersion
+            {
+                minimumSupportedVersion = xcTestMinimumDeploymentTarget
+            } else {
+                minimumSupportedVersion = platform.oldestSupportedVersion
+            }
+
+            let oldestSupportedVersion: PlatformVersion
+            if platform == .macCatalyst {
+                let iOS = self.getDerived(declared: declared, for: .iOS, usingXCTest: usingXCTest)
+                // If there was no deployment target specified for Mac Catalyst, fall back to the iOS deployment target.
+                oldestSupportedVersion = max(minimumSupportedVersion, iOS.version)
+            } else {
+                oldestSupportedVersion = minimumSupportedVersion
+            }
+
+            return SupportedPlatform(
+                platform: platform,
+                version: oldestSupportedVersion,
+                options: []
+            )
+        }
+    }
+}
diff --git a/Sources/PackageGraph/Resolution/ResolvedPackage.swift b/Sources/PackageGraph/Resolution/ResolvedPackage.swift
index fe7939c499f..481f5c7cda5 100644
--- a/Sources/PackageGraph/Resolution/ResolvedPackage.swift
+++ b/Sources/PackageGraph/Resolution/ResolvedPackage.swift
@@ -46,27 +46,39 @@ public final class ResolvedPackage {
     public let defaultLocalization: String?
 
     /// The list of platforms that are supported by this target.
-    public let platforms: SupportedPlatforms
+    public let supportedPlatforms: [SupportedPlatform]
 
     /// If the given package's source is a registry release, this provides additional metadata and signature information.
     public let registryMetadata: RegistryReleaseMetadata?
 
+    private let platformVersionProvider: PlatformVersionProvider
+
     public init(
         package: Package,
         defaultLocalization: String?,
-        platforms: SupportedPlatforms,
+        supportedPlatforms: [SupportedPlatform],
         dependencies: [ResolvedPackage],
         targets: [ResolvedTarget],
         products: [ResolvedProduct],
-        registryMetadata: RegistryReleaseMetadata?
+        registryMetadata: RegistryReleaseMetadata?,
+        platformVersionProvider: PlatformVersionProvider
     ) {
         self.underlyingPackage = package
         self.defaultLocalization = defaultLocalization
-        self.platforms = platforms
+        self.supportedPlatforms = supportedPlatforms
         self.dependencies = dependencies
         self.targets = targets
         self.products = products
         self.registryMetadata = registryMetadata
+        self.platformVersionProvider = platformVersionProvider
+    }    
+
+    public func getSupportedPlatform(for platform: Platform, usingXCTest: Bool) -> SupportedPlatform {
+        self.platformVersionProvider.getDerived(
+            declared: self.supportedPlatforms,
+            for: platform,
+            usingXCTest: usingXCTest
+        )
     }
 }
 
diff --git a/Sources/PackageGraph/Resolution/ResolvedProduct.swift b/Sources/PackageGraph/Resolution/ResolvedProduct.swift
index 4bfb99029a3..489fe468db4 100644
--- a/Sources/PackageGraph/Resolution/ResolvedProduct.swift
+++ b/Sources/PackageGraph/Resolution/ResolvedProduct.swift
@@ -37,7 +37,9 @@ public final class ResolvedProduct {
     public let defaultLocalization: String?
 
     /// The list of platforms that are supported by this product.
-    public let platforms: SupportedPlatforms
+    public let supportedPlatforms: [SupportedPlatform]
+
+    public let platformVersionProvider: PlatformVersionProvider
 
     /// Triple for which this resolved product should be compiled for.
     public let buildTriple: BuildTriple
@@ -67,10 +69,11 @@ public final class ResolvedProduct {
         let defaultLocalization = self.targets.first?.defaultLocalization
         self.defaultLocalization = defaultLocalization
 
-        let platforms = Self.computePlatforms(targets: targets)
-        self.platforms = platforms
+        let (platforms, platformVersionProvider) = Self.computePlatforms(targets: targets)
+        self.supportedPlatforms = platforms
+        self.platformVersionProvider = platformVersionProvider
 
-        self.testEntryPointTarget = underlyingProduct.testEntryPointPath.map { testEntryPointPath in
+        self.testEntryPointTarget = product.testEntryPointPath.map { testEntryPointPath in
             // Create an executable resolved target with the entry point file, adding product's targets as dependencies.
             let dependencies: [Target.Dependency] = product.targets.map { .target($0, conditions: []) }
             let swiftTarget = SwiftTarget(name: product.name,
@@ -81,7 +84,8 @@ public final class ResolvedProduct {
                 target: swiftTarget,
                 dependencies: targets.map { .target($0, conditions: []) },
                 defaultLocalization: defaultLocalization ?? .none, // safe since this is a derived product
-                platforms: platforms
+                supportedPlatforms: platforms,
+                platformVersionProvider: platformVersionProvider
             )
         }
         
@@ -105,33 +109,23 @@ public final class ResolvedProduct {
         let recursiveDependencies = try targets.lazy.flatMap { try $0.recursiveTargetDependencies() }
         return Array(Set(targets).union(recursiveDependencies))
     }
-
-    private static func computePlatforms(targets: [ResolvedTarget]) -> SupportedPlatforms {
-        // merging two sets of supported platforms, preferring the max constraint
-        func merge(into partial: inout [SupportedPlatform], platforms: [SupportedPlatform]) {
-            for platformSupport in platforms {
-                if let existing = partial.firstIndex(where: { $0.platform == platformSupport.platform }) {
-                    if partial[existing].version < platformSupport.version {
-                        partial.remove(at: existing)
-                        partial.append(platformSupport)
-                    }
-                } else {
-                    partial.append(platformSupport)
-                }
-            }
+    private static func computePlatforms(targets: [ResolvedTarget]) -> ([SupportedPlatform], PlatformVersionProvider) {
+        let declaredPlatforms = targets.reduce(into: [SupportedPlatform]()) { partial, item in
+            merge(into: &partial, platforms: item.supportedPlatforms)
         }
 
-        let declared = targets.reduce(into: [SupportedPlatform]()) { partial, item in
-            merge(into: &partial, platforms: item.platforms.declared)
-        }
-
-        return SupportedPlatforms(
-            declared: declared.sorted(by: { $0.platform.name < $1.platform.name })) { declared in
-                let platforms = targets.reduce(into: [SupportedPlatform]()) { partial, item in
-                    merge(into: &partial, platforms: [item.platforms.getDerived(for: declared, usingXCTest: item.type == .test)])
-                }
-                return platforms.first!.version
-            }
+        return (
+            declaredPlatforms.sorted(by: { $0.platform.name < $1.platform.name }),
+            PlatformVersionProvider(implementation: .mergingFromTargets(targets))
+        )
+    }    
+
+    public func getSupportedPlatform(for platform: Platform, usingXCTest: Bool) -> SupportedPlatform {
+        self.platformVersionProvider.getDerived(
+            declared: self.supportedPlatforms,
+            for: platform,
+            usingXCTest: usingXCTest
+        )
     }
 }
 
diff --git a/Sources/PackageGraph/Resolution/ResolvedTarget.swift b/Sources/PackageGraph/Resolution/ResolvedTarget.swift
index eb10eb173c4..7b73ec323f8 100644
--- a/Sources/PackageGraph/Resolution/ResolvedTarget.swift
+++ b/Sources/PackageGraph/Resolution/ResolvedTarget.swift
@@ -139,7 +139,9 @@ public final class ResolvedTarget {
     public let defaultLocalization: String?
 
     /// The list of platforms that are supported by this target.
-    public let platforms: SupportedPlatforms
+    public let supportedPlatforms: [SupportedPlatform]
+
+    private let platformVersionProvider: PlatformVersionProvider
 
     /// Triple for which this resolved target should be compiled for.
     public let buildTriple: BuildTriple
@@ -149,14 +151,24 @@ public final class ResolvedTarget {
         target: Target,
         dependencies: [Dependency],
         defaultLocalization: String?,
-        platforms: SupportedPlatforms
+        supportedPlatforms: [SupportedPlatform],
+        platformVersionProvider: PlatformVersionProvider
     ) {
         self.underlyingTarget = target
         self.dependencies = dependencies
         self.defaultLocalization = defaultLocalization
-        self.platforms = platforms
+        self.supportedPlatforms = supportedPlatforms
+        self.platformVersionProvider = platformVersionProvider
         self.buildTriple = .destination
     }
+
+    public func getSupportedPlatform(for platform: Platform, usingXCTest: Bool) -> SupportedPlatform {
+        self.platformVersionProvider.getDerived(
+            declared: self.supportedPlatforms,
+            for: platform,
+            usingXCTest: usingXCTest
+        )
+    }
 }
 
 extension ResolvedTarget: Hashable {
diff --git a/Sources/PackageModel/Platform.swift b/Sources/PackageModel/Platform.swift
index b74d94b93f9..8cce1a3dc8b 100644
--- a/Sources/PackageModel/Platform.swift
+++ b/Sources/PackageModel/Platform.swift
@@ -52,61 +52,6 @@ public struct Platform: Equatable, Hashable, Codable {
 
 }
 
-public struct SupportedPlatforms {
-    public let declared: [SupportedPlatform]
-    private let derivedXCTestPlatformProvider: ((Platform) -> PlatformVersion?)?
-
-    public init(declared: [SupportedPlatform], derivedXCTestPlatformProvider: ((_ declared: Platform) -> PlatformVersion?)?) {
-        self.declared = declared
-        self.derivedXCTestPlatformProvider = derivedXCTestPlatformProvider
-    }
-
-    /// Returns the supported platform instance for the given platform.
-    public func getDerived(for platform: Platform, usingXCTest: Bool) -> SupportedPlatform {
-        // derived platform based on known minimum deployment target logic
-        if let declaredPlatform = self.declared.first(where: { $0.platform == platform }) {
-            var version = declaredPlatform.version
-
-            if usingXCTest, let xcTestMinimumDeploymentTarget = derivedXCTestPlatformProvider?(platform), version < xcTestMinimumDeploymentTarget {
-                version = xcTestMinimumDeploymentTarget
-            }
-
-            // If the declared version is smaller than the oldest supported one, we raise the derived version to that.
-            if version < platform.oldestSupportedVersion {
-                version = platform.oldestSupportedVersion
-            }
-
-            return SupportedPlatform(
-                platform: declaredPlatform.platform,
-                version: version,
-                options: declaredPlatform.options
-            )
-        } else {
-            let minimumSupportedVersion: PlatformVersion
-            if usingXCTest, let xcTestMinimumDeploymentTarget = derivedXCTestPlatformProvider?(platform), xcTestMinimumDeploymentTarget > platform.oldestSupportedVersion {
-                minimumSupportedVersion = xcTestMinimumDeploymentTarget
-            } else {
-                minimumSupportedVersion = platform.oldestSupportedVersion
-            }
-
-            let oldestSupportedVersion: PlatformVersion
-            if platform == .macCatalyst {
-                let iOS = getDerived(for: .iOS, usingXCTest: usingXCTest)
-                // If there was no deployment target specified for Mac Catalyst, fall back to the iOS deployment target.
-                oldestSupportedVersion = max(minimumSupportedVersion, iOS.version)
-            } else {
-                oldestSupportedVersion = minimumSupportedVersion
-            }
-
-            return SupportedPlatform(
-                platform: platform,
-                version: oldestSupportedVersion,
-                options: []
-            )
-        }
-    }
-}
-
 /// Represents a platform supported by a target.
 public struct SupportedPlatform: Equatable, Codable {
     /// The platform.
diff --git a/Sources/SPMTestSupport/PackageGraphTester.swift b/Sources/SPMTestSupport/PackageGraphTester.swift
index 981f7fc91e0..0d480a6ea96 100644
--- a/Sources/SPMTestSupport/PackageGraphTester.swift
+++ b/Sources/SPMTestSupport/PackageGraphTester.swift
@@ -174,7 +174,7 @@ public final class ResolvedTargetResult {
     }
 
     public func checkDeclaredPlatforms(_ platforms: [String: String], file: StaticString = #file, line: UInt = #line) {
-        let targetPlatforms = Dictionary(uniqueKeysWithValues: target.platforms.declared.map({ ($0.platform.name, $0.version.versionString) }))
+        let targetPlatforms = Dictionary(uniqueKeysWithValues: target.supportedPlatforms.map({ ($0.platform.name, $0.version.versionString) }))
         XCTAssertEqual(platforms, targetPlatforms, file: file, line: line)
     }
 
@@ -182,7 +182,7 @@ public final class ResolvedTargetResult {
         let derived = platforms.map {
             let platform = PlatformRegistry.default.platformByName[$0.key] ?? PackageModel.Platform
                 .custom(name: $0.key, oldestSupportedVersion: $0.value)
-            return self.target.platforms.getDerived(for: platform, usingXCTest: self.target.type == .test)
+            return self.target.getSupportedPlatform(for: platform, usingXCTest: self.target.type == .test)
         }
         let targetPlatforms = Dictionary(
             uniqueKeysWithValues: derived
@@ -192,7 +192,7 @@ public final class ResolvedTargetResult {
     }
 
     public func checkDerivedPlatformOptions(_ platform: PackageModel.Platform, options: [String], file: StaticString = #file, line: UInt = #line) {
-        let platform = target.platforms.getDerived(for: platform, usingXCTest: target.type == .test)
+        let platform = target.getSupportedPlatform(for: platform, usingXCTest: target.type == .test)
         XCTAssertEqual(platform.options, options, file: file, line: line)
     }
 }
@@ -233,21 +233,21 @@ public final class ResolvedProductResult {
     }
 
     public func checkDeclaredPlatforms(_ platforms: [String: String], file: StaticString = #file, line: UInt = #line) {
-        let targetPlatforms = Dictionary(uniqueKeysWithValues: product.platforms.declared.map({ ($0.platform.name, $0.version.versionString) }))
+        let targetPlatforms = Dictionary(uniqueKeysWithValues: product.supportedPlatforms.map({ ($0.platform.name, $0.version.versionString) }))
         XCTAssertEqual(platforms, targetPlatforms, file: file, line: line)
     }
 
     public func checkDerivedPlatforms(_ platforms: [String: String], file: StaticString = #file, line: UInt = #line) {
         let derived = platforms.map {
             let platform = PlatformRegistry.default.platformByName[$0.key] ?? PackageModel.Platform.custom(name: $0.key, oldestSupportedVersion: $0.value)
-            return product.platforms.getDerived(for: platform, usingXCTest: product.isLinkingXCTest)
+            return product.getSupportedPlatform(for: platform, usingXCTest: product.isLinkingXCTest)
         }
         let targetPlatforms = Dictionary(uniqueKeysWithValues: derived.map({ ($0.platform.name, $0.version.versionString) }))
         XCTAssertEqual(platforms, targetPlatforms, file: file, line: line)
     }
 
     public func checkDerivedPlatformOptions(_ platform: PackageModel.Platform, options: [String], file: StaticString = #file, line: UInt = #line) {
-        let platform = product.platforms.getDerived(for: platform, usingXCTest: product.isLinkingXCTest)
+        let platform = product.getSupportedPlatform(for: platform, usingXCTest: product.isLinkingXCTest)
         XCTAssertEqual(platform.options, options, file: file, line: line)
     }
 }
diff --git a/Sources/XCBuildSupport/PIFBuilder.swift b/Sources/XCBuildSupport/PIFBuilder.swift
index ab6d29e78e8..58beb74531d 100644
--- a/Sources/XCBuildSupport/PIFBuilder.swift
+++ b/Sources/XCBuildSupport/PIFBuilder.swift
@@ -271,13 +271,13 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder {
         settings[.SDKROOT] = "auto"
         settings[.SDK_VARIANT] = "auto"
         settings[.SKIP_INSTALL] = "YES"
-        settings[.MACOSX_DEPLOYMENT_TARGET] = package.platforms.deploymentTarget(for: .macOS)
-        settings[.IPHONEOS_DEPLOYMENT_TARGET] = package.platforms.deploymentTarget(for: .iOS)
-        settings[.IPHONEOS_DEPLOYMENT_TARGET, for: .macCatalyst] = package.platforms.deploymentTarget(for: .macCatalyst)
-        settings[.TVOS_DEPLOYMENT_TARGET] = package.platforms.deploymentTarget(for: .tvOS)
-        settings[.WATCHOS_DEPLOYMENT_TARGET] = package.platforms.deploymentTarget(for: .watchOS)
-        settings[.XROS_DEPLOYMENT_TARGET] = package.platforms.deploymentTarget(for: .visionOS)
-        settings[.DRIVERKIT_DEPLOYMENT_TARGET] = package.platforms.deploymentTarget(for: .driverKit)
+        settings[.MACOSX_DEPLOYMENT_TARGET] = package.deploymentTarget(for: .macOS)
+        settings[.IPHONEOS_DEPLOYMENT_TARGET] = package.deploymentTarget(for: .iOS)
+        settings[.IPHONEOS_DEPLOYMENT_TARGET, for: .macCatalyst] = package.deploymentTarget(for: .macCatalyst)
+        settings[.TVOS_DEPLOYMENT_TARGET] = package.deploymentTarget(for: .tvOS)
+        settings[.WATCHOS_DEPLOYMENT_TARGET] = package.deploymentTarget(for: .watchOS)
+        settings[.XROS_DEPLOYMENT_TARGET] = package.deploymentTarget(for: .visionOS)
+        settings[.DRIVERKIT_DEPLOYMENT_TARGET] = package.deploymentTarget(for: .driverKit)
         settings[.DYLIB_INSTALL_NAME_BASE] = "@rpath"
         settings[.USE_HEADERMAP] = "NO"
         settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS] = ["$(inherited)", "SWIFT_PACKAGE"]
@@ -301,7 +301,7 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder {
 
         PlatformRegistry.default.knownPlatforms.forEach {
             guard let platform = PIF.BuildSettings.Platform.from(platform: $0) else { return }
-            let supportedPlatform = package.platforms.getDerived(for: $0, usingXCTest: false)
+            let supportedPlatform = package.getSupportedPlatform(for: $0, usingXCTest: false)
             if !supportedPlatform.options.isEmpty {
                 settings[.SPECIALIZATION_SDK_OPTIONS, for: platform] = supportedPlatform.options
             }
@@ -430,11 +430,11 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder {
 
         // Tests can have a custom deployment target based on the minimum supported by XCTest.
         if mainTarget.underlyingTarget.type == .test {
-            settings[.MACOSX_DEPLOYMENT_TARGET] = mainTarget.platforms.deploymentTarget(for: .macOS, usingXCTest: true)
-            settings[.IPHONEOS_DEPLOYMENT_TARGET] = mainTarget.platforms.deploymentTarget(for: .iOS, usingXCTest: true)
-            settings[.TVOS_DEPLOYMENT_TARGET] = mainTarget.platforms.deploymentTarget(for: .tvOS, usingXCTest: true)
-            settings[.WATCHOS_DEPLOYMENT_TARGET] = mainTarget.platforms.deploymentTarget(for: .watchOS, usingXCTest: true)
-            settings[.XROS_DEPLOYMENT_TARGET] = mainTarget.platforms.deploymentTarget(for: .visionOS, usingXCTest: true)
+            settings[.MACOSX_DEPLOYMENT_TARGET] = mainTarget.deploymentTarget(for: .macOS, usingXCTest: true)
+            settings[.IPHONEOS_DEPLOYMENT_TARGET] = mainTarget.deploymentTarget(for: .iOS, usingXCTest: true)
+            settings[.TVOS_DEPLOYMENT_TARGET] = mainTarget.deploymentTarget(for: .tvOS, usingXCTest: true)
+            settings[.WATCHOS_DEPLOYMENT_TARGET] = mainTarget.deploymentTarget(for: .watchOS, usingXCTest: true)
+            settings[.XROS_DEPLOYMENT_TARGET] = mainTarget.deploymentTarget(for: .visionOS, usingXCTest: true)
         }
 
         if product.type == .executable {
@@ -1417,9 +1417,15 @@ extension Array where Element == ResolvedTarget.Dependency {
     }
 }
 
-extension SupportedPlatforms {
+extension ResolvedPackage {
+    func deploymentTarget(for platform: PackageModel.Platform, usingXCTest: Bool = false) -> String? {
+        return self.getSupportedPlatform(for: platform, usingXCTest: usingXCTest).version.versionString
+    }
+}
+
+extension ResolvedTarget {
     func deploymentTarget(for platform: PackageModel.Platform, usingXCTest: Bool = false) -> String? {
-        return self.getDerived(for: platform, usingXCTest: usingXCTest).version.versionString
+        return self.getSupportedPlatform(for: platform, usingXCTest: usingXCTest).version.versionString
     }
 }
 
diff --git a/Tests/PackageGraphTests/TargetTests.swift b/Tests/PackageGraphTests/TargetTests.swift
index c8c1e4a2f05..0df61ae3c52 100644
--- a/Tests/PackageGraphTests/TargetTests.swift
+++ b/Tests/PackageGraphTests/TargetTests.swift
@@ -30,7 +30,8 @@ private extension ResolvedTarget {
             ),
             dependencies: deps.map { .target($0, conditions: []) },
             defaultLocalization: nil,
-            platforms: .init(declared: [], derivedXCTestPlatformProvider: .none)
+            supportedPlatforms: [],
+            platformVersionProvider: .init(implementation: .minimumDeploymentTargetDefault)
         )
     }
 }