diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 406ff8715d124..da695c1f391a0 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -25154,22 +25154,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
         const inference = context.inferences[index];
         if (!inference.inferredType) {
             let inferredType: Type | undefined;
-            const signature = context.signature;
-            if (signature) {
-                const inferredCovariantType = inference.candidates ? getCovariantInference(inference, signature) : undefined;
-                if (inference.contraCandidates) {
-                    // If we have both co- and contra-variant inferences, we use the co-variant inference if it is not 'never',
-                    // it is a subtype of some contra-variant inference, and no other type parameter is constrained to this type
-                    // parameter and has inferences that would conflict. Otherwise, we use the contra-variant inference.
-                    const useCovariantType = inferredCovariantType && !(inferredCovariantType.flags & TypeFlags.Never) &&
+            let fallbackType: Type | undefined;
+            if (context.signature) {
+                const inferredCovariantType = inference.candidates ? getCovariantInference(inference, context.signature) : undefined;
+                const inferredContravariantType = inference.contraCandidates ? getContravariantInference(inference) : undefined;
+                if (inferredCovariantType || inferredContravariantType) {
+                    // If we have both co- and contra-variant inferences, we prefer the co-variant inference if it is not 'never',
+                    // all co-variant inferences are subtypes of it (i.e. it isn't one of a conflicting set of candidates), it is
+                    // a subtype of some contra-variant inference, and no other type parameter is constrained to this type parameter
+                    // and has inferences that would conflict. Otherwise, we prefer the contra-variant inference.
+                    const preferCovariantType = inferredCovariantType && (!inferredContravariantType ||
+                        !(inferredCovariantType.flags & TypeFlags.Never) &&
                         some(inference.contraCandidates, t => isTypeSubtypeOf(inferredCovariantType, t)) &&
                         every(context.inferences, other =>
                             other !== inference && getConstraintOfTypeParameter(other.typeParameter) !== inference.typeParameter ||
-                            every(other.candidates, t => isTypeSubtypeOf(t, inferredCovariantType)));
-                    inferredType = useCovariantType ? inferredCovariantType : getContravariantInference(inference);
-                }
-                else if (inferredCovariantType) {
-                    inferredType = inferredCovariantType;
+                            every(other.candidates, t => isTypeSubtypeOf(t, inferredCovariantType))));
+                    inferredType = preferCovariantType ? inferredCovariantType : inferredContravariantType;
+                    fallbackType = preferCovariantType ? inferredContravariantType : inferredCovariantType;
                 }
                 else if (context.flags & InferenceFlags.NoDefault) {
                     // We use silentNeverType as the wildcard that signals no inferences.
@@ -25199,7 +25200,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
             if (constraint) {
                 const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper);
                 if (!inferredType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) {
-                    inference.inferredType = inferredType = instantiatedConstraint;
+                    // If the fallback type satisfies the constraint, we pick it. Otherwise, we pick the constraint.
+                    inference.inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint;
                 }
             }
         }
diff --git a/tests/baselines/reference/coAndContraVariantInferences5.symbols b/tests/baselines/reference/coAndContraVariantInferences5.symbols
new file mode 100644
index 0000000000000..b9f6b6fc3081d
--- /dev/null
+++ b/tests/baselines/reference/coAndContraVariantInferences5.symbols
@@ -0,0 +1,66 @@
+=== tests/cases/compiler/coAndContraVariantInferences5.ts ===
+type Thing = 'a' | 'b';
+>Thing : Symbol(Thing, Decl(coAndContraVariantInferences5.ts, 0, 0))
+
+function f(
+>f : Symbol(f, Decl(coAndContraVariantInferences5.ts, 0, 23))
+
+    options: SelectOptions<Thing>,
+>options : Symbol(options, Decl(coAndContraVariantInferences5.ts, 2, 11))
+>SelectOptions : Symbol(SelectOptions, Decl(coAndContraVariantInferences5.ts, 17, 2))
+>Thing : Symbol(Thing, Decl(coAndContraVariantInferences5.ts, 0, 0))
+
+    onChange: (status: Thing | null) => void,
+>onChange : Symbol(onChange, Decl(coAndContraVariantInferences5.ts, 3, 34))
+>status : Symbol(status, Decl(coAndContraVariantInferences5.ts, 4, 15))
+>Thing : Symbol(Thing, Decl(coAndContraVariantInferences5.ts, 0, 0))
+
+): void {
+    select({
+>select : Symbol(select, Decl(coAndContraVariantInferences5.ts, 10, 1))
+
+        options,
+>options : Symbol(options, Decl(coAndContraVariantInferences5.ts, 6, 12))
+
+        onChange,
+>onChange : Symbol(onChange, Decl(coAndContraVariantInferences5.ts, 7, 16))
+
+    });
+}
+
+declare function select<KeyT extends string>(props: SelectProps<KeyT>): void;
+>select : Symbol(select, Decl(coAndContraVariantInferences5.ts, 10, 1))
+>KeyT : Symbol(KeyT, Decl(coAndContraVariantInferences5.ts, 12, 24))
+>props : Symbol(props, Decl(coAndContraVariantInferences5.ts, 12, 45))
+>SelectProps : Symbol(SelectProps, Decl(coAndContraVariantInferences5.ts, 12, 77))
+>KeyT : Symbol(KeyT, Decl(coAndContraVariantInferences5.ts, 12, 24))
+
+type SelectProps<KeyT extends string> = {
+>SelectProps : Symbol(SelectProps, Decl(coAndContraVariantInferences5.ts, 12, 77))
+>KeyT : Symbol(KeyT, Decl(coAndContraVariantInferences5.ts, 14, 17))
+
+    options?: SelectOptions<KeyT>;
+>options : Symbol(options, Decl(coAndContraVariantInferences5.ts, 14, 41))
+>SelectOptions : Symbol(SelectOptions, Decl(coAndContraVariantInferences5.ts, 17, 2))
+>KeyT : Symbol(KeyT, Decl(coAndContraVariantInferences5.ts, 14, 17))
+
+    onChange: (key: KeyT) => void;
+>onChange : Symbol(onChange, Decl(coAndContraVariantInferences5.ts, 15, 34))
+>key : Symbol(key, Decl(coAndContraVariantInferences5.ts, 16, 15))
+>KeyT : Symbol(KeyT, Decl(coAndContraVariantInferences5.ts, 14, 17))
+
+};
+
+type SelectOptions<KeyT extends string> =
+>SelectOptions : Symbol(SelectOptions, Decl(coAndContraVariantInferences5.ts, 17, 2))
+>KeyT : Symbol(KeyT, Decl(coAndContraVariantInferences5.ts, 19, 19))
+
+    | Array<{key: KeyT}>
+>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
+>key : Symbol(key, Decl(coAndContraVariantInferences5.ts, 20, 13))
+>KeyT : Symbol(KeyT, Decl(coAndContraVariantInferences5.ts, 19, 19))
+
+    | Array<KeyT>;
+>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
+>KeyT : Symbol(KeyT, Decl(coAndContraVariantInferences5.ts, 19, 19))
+
diff --git a/tests/baselines/reference/coAndContraVariantInferences5.types b/tests/baselines/reference/coAndContraVariantInferences5.types
new file mode 100644
index 0000000000000..4bcacf5535e32
--- /dev/null
+++ b/tests/baselines/reference/coAndContraVariantInferences5.types
@@ -0,0 +1,53 @@
+=== tests/cases/compiler/coAndContraVariantInferences5.ts ===
+type Thing = 'a' | 'b';
+>Thing : "a" | "b"
+
+function f(
+>f : (options: SelectOptions<Thing>, onChange: (status: Thing | null) => void) => void
+
+    options: SelectOptions<Thing>,
+>options : SelectOptions<Thing>
+
+    onChange: (status: Thing | null) => void,
+>onChange : (status: Thing | null) => void
+>status : Thing | null
+
+): void {
+    select({
+>select({        options,        onChange,    }) : void
+>select : <KeyT extends string>(props: SelectProps<KeyT>) => void
+>{        options,        onChange,    } : { options: SelectOptions<Thing>; onChange: (status: Thing | null) => void; }
+
+        options,
+>options : SelectOptions<Thing>
+
+        onChange,
+>onChange : (status: Thing | null) => void
+
+    });
+}
+
+declare function select<KeyT extends string>(props: SelectProps<KeyT>): void;
+>select : <KeyT extends string>(props: SelectProps<KeyT>) => void
+>props : SelectProps<KeyT>
+
+type SelectProps<KeyT extends string> = {
+>SelectProps : SelectProps<KeyT>
+
+    options?: SelectOptions<KeyT>;
+>options : SelectOptions<KeyT> | undefined
+
+    onChange: (key: KeyT) => void;
+>onChange : (key: KeyT) => void
+>key : KeyT
+
+};
+
+type SelectOptions<KeyT extends string> =
+>SelectOptions : SelectOptions<KeyT>
+
+    | Array<{key: KeyT}>
+>key : KeyT
+
+    | Array<KeyT>;
+
diff --git a/tests/cases/compiler/coAndContraVariantInferences5.ts b/tests/cases/compiler/coAndContraVariantInferences5.ts
new file mode 100644
index 0000000000000..a569065ea146e
--- /dev/null
+++ b/tests/cases/compiler/coAndContraVariantInferences5.ts
@@ -0,0 +1,25 @@
+// @strict: true
+// @noEmit: true
+
+type Thing = 'a' | 'b';
+
+function f(
+    options: SelectOptions<Thing>,
+    onChange: (status: Thing | null) => void,
+): void {
+    select({
+        options,
+        onChange,
+    });
+}
+
+declare function select<KeyT extends string>(props: SelectProps<KeyT>): void;
+
+type SelectProps<KeyT extends string> = {
+    options?: SelectOptions<KeyT>;
+    onChange: (key: KeyT) => void;
+};
+
+type SelectOptions<KeyT extends string> =
+    | Array<{key: KeyT}>
+    | Array<KeyT>;