diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index c5701087ebfd4..790f97db3eb8e 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -42606,6 +42606,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
         return undefined;
     }
 
+    function getSignaturesFromCallLike(node: CallLikeExpression): readonly Signature[] {
+        switch (node.kind) {
+            case SyntaxKind.CallExpression:
+            case SyntaxKind.Decorator:
+                return getSignaturesOfType(
+                    getTypeOfExpression(node.expression),
+                    SignatureKind.Call,
+                );
+            case SyntaxKind.NewExpression:
+                return getSignaturesOfType(
+                    getTypeOfExpression(node.expression),
+                    SignatureKind.Construct,
+                );
+            case SyntaxKind.JsxSelfClosingElement:
+            case SyntaxKind.JsxOpeningElement:
+                if (isJsxIntrinsicTagName(node.tagName)) return [];
+                return getSignaturesOfType(
+                    getTypeOfExpression(node.tagName),
+                    SignatureKind.Call,
+                );
+            case SyntaxKind.TaggedTemplateExpression:
+                return getSignaturesOfType(
+                    getTypeOfExpression(node.tag),
+                    SignatureKind.Call,
+                );
+            case SyntaxKind.BinaryExpression:
+            case SyntaxKind.JsxOpeningFragment:
+                return [];
+        }
+    }
+
+    function getTypeParameterConstraintForPositionAcrossSignatures(signatures: readonly Signature[], position: number) {
+        const relevantTypeParameterConstraints = flatMap(signatures, signature => {
+            const relevantTypeParameter = signature.typeParameters?.[position];
+            if (relevantTypeParameter === undefined) return [];
+            const relevantConstraint = getConstraintOfTypeParameter(relevantTypeParameter);
+            if (relevantConstraint === undefined) return [];
+            return [relevantConstraint];
+        });
+        return getUnionType(relevantTypeParameterConstraints);
+    }
+
     function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) {
         checkGrammarTypeArguments(node, node.typeArguments);
         if (node.kind === SyntaxKind.TypeReference && !isInJSFile(node) && !isInJSDoc(node) && node.typeArguments && node.typeName.end !== node.typeArguments.pos) {
@@ -42644,12 +42686,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
     }
 
     function getTypeArgumentConstraint(node: TypeNode): Type | undefined {
-        const typeReferenceNode = tryCast(node.parent, isTypeReferenceType);
-        if (!typeReferenceNode) return undefined;
-        const typeParameters = getTypeParametersForTypeReferenceOrImport(typeReferenceNode);
-        if (!typeParameters) return undefined;
-        const constraint = getConstraintOfTypeParameter(typeParameters[typeReferenceNode.typeArguments!.indexOf(node)]);
-        return constraint && instantiateType(constraint, createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters)));
+        let typeArgumentPosition;
+        if (
+            "typeArguments" in node.parent && // eslint-disable-line local/no-in-operator
+            Array.isArray(node.parent.typeArguments)
+        ) {
+            typeArgumentPosition = node.parent.typeArguments.indexOf(node);
+        }
+
+        if (typeArgumentPosition !== undefined) {
+            // The node could be a type argument of a call, a `new` expression, a decorator, an
+            // instantiation expression, or a generic type instantiation.
+
+            if (isCallLikeExpression(node.parent)) {
+                return getTypeParameterConstraintForPositionAcrossSignatures(
+                    getSignaturesFromCallLike(node.parent),
+                    typeArgumentPosition,
+                );
+            }
+
+            if (isDecorator(node.parent.parent)) {
+                return getTypeParameterConstraintForPositionAcrossSignatures(
+                    getSignaturesFromCallLike(node.parent.parent),
+                    typeArgumentPosition,
+                );
+            }
+
+            if (isExpressionWithTypeArguments(node.parent) && isExpressionStatement(node.parent.parent)) {
+                const uninstantiatedType = checkExpression(node.parent.expression);
+
+                const callConstraint = getTypeParameterConstraintForPositionAcrossSignatures(
+                    getSignaturesOfType(uninstantiatedType, SignatureKind.Call),
+                    typeArgumentPosition,
+                );
+                const constructConstraint = getTypeParameterConstraintForPositionAcrossSignatures(
+                    getSignaturesOfType(uninstantiatedType, SignatureKind.Construct),
+                    typeArgumentPosition,
+                );
+
+                // An instantiation expression instantiates both call and construct signatures, so
+                // if both exist type arguments must be assignable to both constraints.
+                if (constructConstraint.flags & TypeFlags.Never) return callConstraint;
+                if (callConstraint.flags & TypeFlags.Never) return constructConstraint;
+                return getIntersectionType([callConstraint, constructConstraint]);
+            }
+
+            if (isTypeReferenceType(node.parent)) {
+                const typeParameters = getTypeParametersForTypeReferenceOrImport(node.parent);
+                if (!typeParameters) return undefined;
+                const relevantTypeParameter = typeParameters[typeArgumentPosition];
+                const constraint = getConstraintOfTypeParameter(relevantTypeParameter);
+                return constraint && instantiateType(
+                    constraint,
+                    createTypeMapper(typeParameters, getEffectiveTypeArguments(node.parent, typeParameters)),
+                );
+            }
+        }
     }
 
     function checkTypeQuery(node: TypeQueryNode) {
diff --git a/src/services/completions.ts b/src/services/completions.ts
index dc01ea8ede4b9..9e90922d445d4 100644
--- a/src/services/completions.ts
+++ b/src/services/completions.ts
@@ -256,7 +256,6 @@ import {
     isTypeOnlyImportDeclaration,
     isTypeOnlyImportOrExportDeclaration,
     isTypeParameterDeclaration,
-    isTypeReferenceType,
     isValidTypeOnlyAliasUseSite,
     isVariableDeclaration,
     isVariableLike,
@@ -5769,8 +5768,9 @@ function tryGetTypeLiteralNode(node: Node): TypeLiteralNode | undefined {
 function getConstraintOfTypeArgumentProperty(node: Node, checker: TypeChecker): Type | undefined {
     if (!node) return undefined;
 
-    if (isTypeNode(node) && isTypeReferenceType(node.parent)) {
-        return checker.getTypeArgumentConstraint(node);
+    if (isTypeNode(node)) {
+        const constraint = checker.getTypeArgumentConstraint(node);
+        if (constraint) return constraint;
     }
 
     const t = getConstraintOfTypeArgumentProperty(node.parent, checker);
diff --git a/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter10.ts b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter10.ts
new file mode 100644
index 0000000000000..892e88a882558
--- /dev/null
+++ b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter10.ts
@@ -0,0 +1,38 @@
+/// <reference path="fourslash.ts" />
+
+////interface Foo {
+////    one: string;
+////    two: number;
+////}
+////interface Bar {
+////    three: boolean;
+////    four: {
+////        five: unknown;
+////    };
+////}
+////
+////function a<T extends Foo>() {}
+////a<{/*0*/}>();
+////
+////var b = () => <T extends Foo>() => {};
+////b()<{/*1*/}>();
+////
+////declare function c<T extends Foo>(): void
+////declare function c<T extends Bar>(): void
+////c<{/*2*/}>();
+////
+////function d<T extends Foo, U extends Bar>() {}
+////d<{/*3*/}, {/*4*/}>();
+////d<Foo, { four: {/*5*/} }>();
+////
+////(<T extends Foo>() => {})<{/*6*/}>();
+
+verify.completions(
+    { marker: "0", unsorted: ["one", "two"], isNewIdentifierLocation: true },
+    { marker: "1", unsorted: ["one", "two"], isNewIdentifierLocation: true },
+    { marker: "2", unsorted: ["one", "two", "three", "four"], isNewIdentifierLocation: true },
+    { marker: "3", unsorted: ["one", "two"], isNewIdentifierLocation: true },
+    { marker: "4", unsorted: ["three", "four"], isNewIdentifierLocation: true },
+    { marker: "5", unsorted: ["five"], isNewIdentifierLocation: true },
+    { marker: "6", unsorted: ["one", "two"], isNewIdentifierLocation: true },
+);
diff --git a/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter11.ts b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter11.ts
new file mode 100644
index 0000000000000..634746dd38582
--- /dev/null
+++ b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter11.ts
@@ -0,0 +1,32 @@
+/// <reference path="fourslash.ts" />
+
+////interface Foo {
+////    one: string;
+////    two: number;
+////}
+////interface Bar {
+////    three: boolean;
+////    four: symbol;
+////}
+////
+////class A<T extends Foo> {}
+////new A<{/*0*/}>();
+////
+////class B<T extends Foo, U extends Bar> {}
+////new B<{/*1*/}, {/*2*/}>();
+////
+////declare const C: {
+////   new <T extends Foo>(): unknown
+////   new <T extends Bar>(): unknown
+////}
+////new C<{/*3*/}>()
+////
+////new (class <T extends Foo> {})<{/*4*/}>();
+
+verify.completions(
+    { marker: "0", unsorted: ["one", "two"], isNewIdentifierLocation: true },
+    { marker: "1", unsorted: ["one", "two"], isNewIdentifierLocation: true },
+    { marker: "2", unsorted: ["three", "four"], isNewIdentifierLocation: true },
+    { marker: "3", unsorted: ["one", "two", "three", "four"], isNewIdentifierLocation: true },
+    { marker: "4", unsorted: ["one", "two"], isNewIdentifierLocation: true },
+);
diff --git a/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter12.ts b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter12.ts
new file mode 100644
index 0000000000000..9bf8ec21afaae
--- /dev/null
+++ b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter12.ts
@@ -0,0 +1,25 @@
+/// <reference path="fourslash.ts" />
+
+////interface Foo {
+////    kind: 'foo';
+////    one: string;
+////}
+////interface Bar {
+////    kind: 'bar';
+////    two: number;
+////}
+////
+////declare function a<T extends Foo>(): void
+////declare function a<T extends Bar>(): void
+////a<{ kind: 'bar', /*0*/ }>();
+////
+////declare function b<T extends Foo>(kind: 'foo'): void
+////declare function b<T extends Bar>(kind: 'bar'): void
+////b<{/*1*/}>('bar');
+
+// The completion lists are unfortunately not narrowed here (ideally only
+// properties of `Bar` would be suggested).
+verify.completions(
+  { marker: "0", unsorted: ["one", "two"], isNewIdentifierLocation: true },
+  { marker: "1", unsorted: ["kind", "one", "two"], isNewIdentifierLocation: true },
+);
diff --git a/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter13.ts b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter13.ts
new file mode 100644
index 0000000000000..5797134b2b15e
--- /dev/null
+++ b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter13.ts
@@ -0,0 +1,18 @@
+/// <reference path="fourslash.ts" />
+
+// @jsx: preserve
+// @filename: a.tsx
+////interface Foo {
+////    one: string;
+////    two: number;
+////}
+////
+////const Component = <T extends Foo>() => <></>;
+////
+////<Component<{/*0*/}>></Component>;
+////<Component<{/*1*/}>/>;
+
+verify.completions(
+  { marker: "0", unsorted: ["one", "two"], isNewIdentifierLocation: true },
+  { marker: "1", unsorted: ["one", "two"], isNewIdentifierLocation: true },
+);
diff --git a/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter14.ts b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter14.ts
new file mode 100644
index 0000000000000..79aa45875715e
--- /dev/null
+++ b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter14.ts
@@ -0,0 +1,10 @@
+/// <reference path="fourslash.ts" />
+
+////interface Foo {
+////   one: string;
+////   two: number;
+////}
+////declare function f<T extends Foo>(x: TemplateStringsArray): void;
+////f<{/*0*/}>``;
+
+verify.completions({ marker: "0", unsorted: ["one", "two"], isNewIdentifierLocation: true });
diff --git a/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter15.ts b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter15.ts
new file mode 100644
index 0000000000000..352facb90a46d
--- /dev/null
+++ b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter15.ts
@@ -0,0 +1,15 @@
+/// <reference path="fourslash.ts" />
+
+////interface Foo {
+////   one: string;
+////   two: number;
+////}
+////
+////declare function decorator<T extends Foo>(originalMethod: unknown, _context: unknown): never
+////
+////class {
+////   @decorator<{/*0*/}>
+////   method() {}
+////}
+
+verify.completions({ marker: "0", unsorted: ["one", "two"], isNewIdentifierLocation: true });
diff --git a/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter16.ts b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter16.ts
new file mode 100644
index 0000000000000..4c32c2d19fc22
--- /dev/null
+++ b/tests/cases/fourslash/completionListInTypeLiteralInTypeParameter16.ts
@@ -0,0 +1,35 @@
+/// <reference path="fourslash.ts" />
+
+////interface Foo {
+////    one: string;
+////    two: number;
+////}
+////interface Bar {
+////    three: boolean;
+////    four: {
+////        five: unknown;
+////    };
+////}
+////
+////(<T extends Foo>() => {})<{/*0*/}>;
+////
+////(class <T extends Foo>{})<{/*1*/}>;
+////
+////declare const a: {
+////    new <T extends Foo>(): {};
+////    <T extends Bar>(): {};
+////}
+////a<{/*2*/}>;
+////
+////declare const b: {
+////    new <T extends { one: true }>(): {};
+////    <T extends { one: false }>(): {};
+////}
+////b<{/*3*/}>;
+
+verify.completions(
+    { marker: "0", unsorted: ["one", "two"], isNewIdentifierLocation: true },
+    { marker: "1", unsorted: ["one", "two"], isNewIdentifierLocation: true },
+    { marker: "2", unsorted: ["one", "two", "three", "four"], isNewIdentifierLocation: true },
+    { marker: "3", unsorted: [], isNewIdentifierLocation: true },
+);