diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index fe2ce42652af4..4d397bcc71cf8 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -10365,7 +10365,15 @@ namespace ts {
             if (typeVariable) {
                 const mappedTypeVariable = instantiateType(typeVariable, mapper);
                 if (typeVariable !== mappedTypeVariable) {
-                    return mapType(mappedTypeVariable, t => {
+                    // If we are already in the process of creating an instantiation of this mapped type,
+                    // return the error type. This situation only arises if we are instantiating the mapped
+                    // type for an array or tuple type, as we then need to eagerly resolve the (possibly
+                    // circular) element type(s).
+                    if (type.instantiating) {
+                        return errorType;
+                    }
+                    type.instantiating = true;
+                    const result = mapType(mappedTypeVariable, t => {
                         if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType) {
                             const replacementMapper = createReplacementMapper(typeVariable, t, mapper);
                             return isArrayType(t) ? createArrayType(instantiateMappedTypeTemplate(type, numberType, /*isOptional*/ true, replacementMapper)) :
@@ -10375,6 +10383,8 @@ namespace ts {
                         }
                         return t;
                     });
+                    type.instantiating = false;
+                    return result;
                 }
             }
             return instantiateAnonymousType(type, mapper);
@@ -14212,12 +14222,26 @@ namespace ts {
             return undefined;
         }
 
+        function isDiscriminantType(type: Type): boolean {
+            if (type.flags & TypeFlags.Union) {
+                if (type.flags & (TypeFlags.Boolean | TypeFlags.EnumLiteral)) {
+                    return true;
+                }
+                let combined = 0;
+                for (const t of (<UnionType>type).types) combined |= t.flags;
+                if (combined & TypeFlags.Unit && !(combined & TypeFlags.Instantiable)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
         function isDiscriminantProperty(type: Type | undefined, name: __String) {
             if (type && type.flags & TypeFlags.Union) {
                 const prop = getUnionOrIntersectionProperty(<UnionType>type, name);
                 if (prop && getCheckFlags(prop) & CheckFlags.SyntheticProperty) {
                     if ((<TransientSymbol>prop).isDiscriminantProperty === undefined) {
-                        (<TransientSymbol>prop).isDiscriminantProperty = !!((<TransientSymbol>prop).checkFlags & CheckFlags.HasNonUniformType) && isLiteralType(getTypeOfSymbol(prop));
+                        (<TransientSymbol>prop).isDiscriminantProperty = !!((<TransientSymbol>prop).checkFlags & CheckFlags.HasNonUniformType) && isDiscriminantType(getTypeOfSymbol(prop));
                     }
                     return !!(<TransientSymbol>prop).isDiscriminantProperty;
                 }
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index 3bd103579f1b3..5763ab3eff0f3 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -4074,6 +4074,7 @@ namespace ts {
         templateType?: Type;
         modifiersType?: Type;
         resolvedApparentType?: Type;
+        instantiating?: boolean;
     }
 
     export interface EvolvingArrayType extends ObjectType {
diff --git a/tests/baselines/reference/discriminatedUnionTypes2.errors.txt b/tests/baselines/reference/discriminatedUnionTypes2.errors.txt
new file mode 100644
index 0000000000000..c50f7a2767aac
--- /dev/null
+++ b/tests/baselines/reference/discriminatedUnionTypes2.errors.txt
@@ -0,0 +1,86 @@
+tests/cases/conformance/types/union/discriminatedUnionTypes2.ts(27,30): error TS2322: Type '{ a: null; b: string; c: number; }' is not assignable to type '{ a: null; b: string; } | { a: string; c: number; }'.
+  Object literal may only specify known properties, and 'c' does not exist in type '{ a: null; b: string; }'.
+tests/cases/conformance/types/union/discriminatedUnionTypes2.ts(32,11): error TS2339: Property 'b' does not exist on type '{ a: 0; b: string; } | { a: T; c: number; }'.
+  Property 'b' does not exist on type '{ a: T; c: number; }'.
+
+
+==== tests/cases/conformance/types/union/discriminatedUnionTypes2.ts (2 errors) ====
+    function f10(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) {
+        if (x.kind === false) {
+            x.a;
+        }
+        else if (x.kind === true) {
+            x.b;
+        }
+        else {
+            x.c;
+        }
+    }
+    
+    function f11(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) {
+        switch (x.kind) {
+            case false:
+                x.a;
+                break;
+            case true:
+                x.b;
+                break;
+            default:
+                x.c;
+        }
+    }
+    
+    function f13(x: { a: null; b: string } | { a: string, c: number }) {
+        x = { a: null, b: "foo", c: 4};  // Error
+                                 ~~~~
+!!! error TS2322: Type '{ a: null; b: string; c: number; }' is not assignable to type '{ a: null; b: string; } | { a: string; c: number; }'.
+!!! error TS2322:   Object literal may only specify known properties, and 'c' does not exist in type '{ a: null; b: string; }'.
+    }
+    
+    function f14<T>(x: { a: 0; b: string } | { a: T, c: number }) {
+        if (x.a === 0) {
+            x.b;  // Error
+              ~
+!!! error TS2339: Property 'b' does not exist on type '{ a: 0; b: string; } | { a: T; c: number; }'.
+!!! error TS2339:   Property 'b' does not exist on type '{ a: T; c: number; }'.
+        }
+    }
+    
+    type Result<T> = { error?: undefined, value: T } | { error: Error };
+    
+    function f15(x: Result<number>) {
+        if (!x.error) {
+            x.value;
+        }
+        else {
+            x.error.message;
+        }
+    }
+    
+    f15({ value: 10 });
+    f15({ error: new Error("boom") });
+    
+    // Repro from #24193
+    
+    interface WithError {
+        error: Error
+        data: null
+    }
+    
+    interface WithoutError<Data> {
+        error: null
+        data: Data
+    }
+    
+    type DataCarrier<Data> = WithError | WithoutError<Data>
+    
+    function f20<Data>(carrier: DataCarrier<Data>) {
+        if (carrier.error === null) {
+            const error: null = carrier.error
+            const data: Data = carrier.data
+        } else {
+            const error: Error = carrier.error
+            const data: null = carrier.data
+        }
+    }
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/discriminatedUnionTypes2.js b/tests/baselines/reference/discriminatedUnionTypes2.js
new file mode 100644
index 0000000000000..e2b5d99ddcd84
--- /dev/null
+++ b/tests/baselines/reference/discriminatedUnionTypes2.js
@@ -0,0 +1,128 @@
+//// [discriminatedUnionTypes2.ts]
+function f10(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) {
+    if (x.kind === false) {
+        x.a;
+    }
+    else if (x.kind === true) {
+        x.b;
+    }
+    else {
+        x.c;
+    }
+}
+
+function f11(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) {
+    switch (x.kind) {
+        case false:
+            x.a;
+            break;
+        case true:
+            x.b;
+            break;
+        default:
+            x.c;
+    }
+}
+
+function f13(x: { a: null; b: string } | { a: string, c: number }) {
+    x = { a: null, b: "foo", c: 4};  // Error
+}
+
+function f14<T>(x: { a: 0; b: string } | { a: T, c: number }) {
+    if (x.a === 0) {
+        x.b;  // Error
+    }
+}
+
+type Result<T> = { error?: undefined, value: T } | { error: Error };
+
+function f15(x: Result<number>) {
+    if (!x.error) {
+        x.value;
+    }
+    else {
+        x.error.message;
+    }
+}
+
+f15({ value: 10 });
+f15({ error: new Error("boom") });
+
+// Repro from #24193
+
+interface WithError {
+    error: Error
+    data: null
+}
+
+interface WithoutError<Data> {
+    error: null
+    data: Data
+}
+
+type DataCarrier<Data> = WithError | WithoutError<Data>
+
+function f20<Data>(carrier: DataCarrier<Data>) {
+    if (carrier.error === null) {
+        const error: null = carrier.error
+        const data: Data = carrier.data
+    } else {
+        const error: Error = carrier.error
+        const data: null = carrier.data
+    }
+}
+
+
+//// [discriminatedUnionTypes2.js]
+"use strict";
+function f10(x) {
+    if (x.kind === false) {
+        x.a;
+    }
+    else if (x.kind === true) {
+        x.b;
+    }
+    else {
+        x.c;
+    }
+}
+function f11(x) {
+    switch (x.kind) {
+        case false:
+            x.a;
+            break;
+        case true:
+            x.b;
+            break;
+        default:
+            x.c;
+    }
+}
+function f13(x) {
+    x = { a: null, b: "foo", c: 4 }; // Error
+}
+function f14(x) {
+    if (x.a === 0) {
+        x.b; // Error
+    }
+}
+function f15(x) {
+    if (!x.error) {
+        x.value;
+    }
+    else {
+        x.error.message;
+    }
+}
+f15({ value: 10 });
+f15({ error: new Error("boom") });
+function f20(carrier) {
+    if (carrier.error === null) {
+        var error = carrier.error;
+        var data = carrier.data;
+    }
+    else {
+        var error = carrier.error;
+        var data = carrier.data;
+    }
+}
diff --git a/tests/baselines/reference/discriminatedUnionTypes2.symbols b/tests/baselines/reference/discriminatedUnionTypes2.symbols
new file mode 100644
index 0000000000000..38cfcb0b23ab4
--- /dev/null
+++ b/tests/baselines/reference/discriminatedUnionTypes2.symbols
@@ -0,0 +1,227 @@
+=== tests/cases/conformance/types/union/discriminatedUnionTypes2.ts ===
+function f10(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) {
+>f10 : Symbol(f10, Decl(discriminatedUnionTypes2.ts, 0, 0))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 0, 13))
+>kind : Symbol(kind, Decl(discriminatedUnionTypes2.ts, 0, 18))
+>a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 0, 31))
+>kind : Symbol(kind, Decl(discriminatedUnionTypes2.ts, 0, 47))
+>b : Symbol(b, Decl(discriminatedUnionTypes2.ts, 0, 59))
+>kind : Symbol(kind, Decl(discriminatedUnionTypes2.ts, 0, 75))
+>c : Symbol(c, Decl(discriminatedUnionTypes2.ts, 0, 89))
+
+    if (x.kind === false) {
+>x.kind : Symbol(kind, Decl(discriminatedUnionTypes2.ts, 0, 18), Decl(discriminatedUnionTypes2.ts, 0, 47), Decl(discriminatedUnionTypes2.ts, 0, 75))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 0, 13))
+>kind : Symbol(kind, Decl(discriminatedUnionTypes2.ts, 0, 18), Decl(discriminatedUnionTypes2.ts, 0, 47), Decl(discriminatedUnionTypes2.ts, 0, 75))
+
+        x.a;
+>x.a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 0, 31))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 0, 13))
+>a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 0, 31))
+    }
+    else if (x.kind === true) {
+>x.kind : Symbol(kind, Decl(discriminatedUnionTypes2.ts, 0, 47), Decl(discriminatedUnionTypes2.ts, 0, 75))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 0, 13))
+>kind : Symbol(kind, Decl(discriminatedUnionTypes2.ts, 0, 47), Decl(discriminatedUnionTypes2.ts, 0, 75))
+
+        x.b;
+>x.b : Symbol(b, Decl(discriminatedUnionTypes2.ts, 0, 59))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 0, 13))
+>b : Symbol(b, Decl(discriminatedUnionTypes2.ts, 0, 59))
+    }
+    else {
+        x.c;
+>x.c : Symbol(c, Decl(discriminatedUnionTypes2.ts, 0, 89))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 0, 13))
+>c : Symbol(c, Decl(discriminatedUnionTypes2.ts, 0, 89))
+    }
+}
+
+function f11(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) {
+>f11 : Symbol(f11, Decl(discriminatedUnionTypes2.ts, 10, 1))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 12, 13))
+>kind : Symbol(kind, Decl(discriminatedUnionTypes2.ts, 12, 18))
+>a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 12, 31))
+>kind : Symbol(kind, Decl(discriminatedUnionTypes2.ts, 12, 47))
+>b : Symbol(b, Decl(discriminatedUnionTypes2.ts, 12, 59))
+>kind : Symbol(kind, Decl(discriminatedUnionTypes2.ts, 12, 75))
+>c : Symbol(c, Decl(discriminatedUnionTypes2.ts, 12, 89))
+
+    switch (x.kind) {
+>x.kind : Symbol(kind, Decl(discriminatedUnionTypes2.ts, 12, 18), Decl(discriminatedUnionTypes2.ts, 12, 47), Decl(discriminatedUnionTypes2.ts, 12, 75))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 12, 13))
+>kind : Symbol(kind, Decl(discriminatedUnionTypes2.ts, 12, 18), Decl(discriminatedUnionTypes2.ts, 12, 47), Decl(discriminatedUnionTypes2.ts, 12, 75))
+
+        case false:
+            x.a;
+>x.a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 12, 31))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 12, 13))
+>a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 12, 31))
+
+            break;
+        case true:
+            x.b;
+>x.b : Symbol(b, Decl(discriminatedUnionTypes2.ts, 12, 59))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 12, 13))
+>b : Symbol(b, Decl(discriminatedUnionTypes2.ts, 12, 59))
+
+            break;
+        default:
+            x.c;
+>x.c : Symbol(c, Decl(discriminatedUnionTypes2.ts, 12, 89))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 12, 13))
+>c : Symbol(c, Decl(discriminatedUnionTypes2.ts, 12, 89))
+    }
+}
+
+function f13(x: { a: null; b: string } | { a: string, c: number }) {
+>f13 : Symbol(f13, Decl(discriminatedUnionTypes2.ts, 23, 1))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 25, 13))
+>a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 25, 17))
+>b : Symbol(b, Decl(discriminatedUnionTypes2.ts, 25, 26))
+>a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 25, 42))
+>c : Symbol(c, Decl(discriminatedUnionTypes2.ts, 25, 53))
+
+    x = { a: null, b: "foo", c: 4};  // Error
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 25, 13))
+>a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 26, 9))
+>b : Symbol(b, Decl(discriminatedUnionTypes2.ts, 26, 18))
+>c : Symbol(c, Decl(discriminatedUnionTypes2.ts, 26, 28))
+}
+
+function f14<T>(x: { a: 0; b: string } | { a: T, c: number }) {
+>f14 : Symbol(f14, Decl(discriminatedUnionTypes2.ts, 27, 1))
+>T : Symbol(T, Decl(discriminatedUnionTypes2.ts, 29, 13))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 29, 16))
+>a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 29, 20))
+>b : Symbol(b, Decl(discriminatedUnionTypes2.ts, 29, 26))
+>a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 29, 42))
+>T : Symbol(T, Decl(discriminatedUnionTypes2.ts, 29, 13))
+>c : Symbol(c, Decl(discriminatedUnionTypes2.ts, 29, 48))
+
+    if (x.a === 0) {
+>x.a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 29, 20), Decl(discriminatedUnionTypes2.ts, 29, 42))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 29, 16))
+>a : Symbol(a, Decl(discriminatedUnionTypes2.ts, 29, 20), Decl(discriminatedUnionTypes2.ts, 29, 42))
+
+        x.b;  // Error
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 29, 16))
+    }
+}
+
+type Result<T> = { error?: undefined, value: T } | { error: Error };
+>Result : Symbol(Result, Decl(discriminatedUnionTypes2.ts, 33, 1))
+>T : Symbol(T, Decl(discriminatedUnionTypes2.ts, 35, 12))
+>error : Symbol(error, Decl(discriminatedUnionTypes2.ts, 35, 18))
+>value : Symbol(value, Decl(discriminatedUnionTypes2.ts, 35, 37))
+>T : Symbol(T, Decl(discriminatedUnionTypes2.ts, 35, 12))
+>error : Symbol(error, Decl(discriminatedUnionTypes2.ts, 35, 52))
+>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
+
+function f15(x: Result<number>) {
+>f15 : Symbol(f15, Decl(discriminatedUnionTypes2.ts, 35, 68))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 37, 13))
+>Result : Symbol(Result, Decl(discriminatedUnionTypes2.ts, 33, 1))
+
+    if (!x.error) {
+>x.error : Symbol(error, Decl(discriminatedUnionTypes2.ts, 35, 52), Decl(discriminatedUnionTypes2.ts, 35, 18))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 37, 13))
+>error : Symbol(error, Decl(discriminatedUnionTypes2.ts, 35, 52), Decl(discriminatedUnionTypes2.ts, 35, 18))
+
+        x.value;
+>x.value : Symbol(value, Decl(discriminatedUnionTypes2.ts, 35, 37))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 37, 13))
+>value : Symbol(value, Decl(discriminatedUnionTypes2.ts, 35, 37))
+    }
+    else {
+        x.error.message;
+>x.error.message : Symbol(Error.message, Decl(lib.es5.d.ts, --, --))
+>x.error : Symbol(error, Decl(discriminatedUnionTypes2.ts, 35, 52))
+>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 37, 13))
+>error : Symbol(error, Decl(discriminatedUnionTypes2.ts, 35, 52))
+>message : Symbol(Error.message, Decl(lib.es5.d.ts, --, --))
+    }
+}
+
+f15({ value: 10 });
+>f15 : Symbol(f15, Decl(discriminatedUnionTypes2.ts, 35, 68))
+>value : Symbol(value, Decl(discriminatedUnionTypes2.ts, 46, 5))
+
+f15({ error: new Error("boom") });
+>f15 : Symbol(f15, Decl(discriminatedUnionTypes2.ts, 35, 68))
+>error : Symbol(error, Decl(discriminatedUnionTypes2.ts, 47, 5))
+>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
+
+// Repro from #24193
+
+interface WithError {
+>WithError : Symbol(WithError, Decl(discriminatedUnionTypes2.ts, 47, 34))
+
+    error: Error
+>error : Symbol(WithError.error, Decl(discriminatedUnionTypes2.ts, 51, 21))
+>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
+
+    data: null
+>data : Symbol(WithError.data, Decl(discriminatedUnionTypes2.ts, 52, 16))
+}
+
+interface WithoutError<Data> {
+>WithoutError : Symbol(WithoutError, Decl(discriminatedUnionTypes2.ts, 54, 1))
+>Data : Symbol(Data, Decl(discriminatedUnionTypes2.ts, 56, 23))
+
+    error: null
+>error : Symbol(WithoutError.error, Decl(discriminatedUnionTypes2.ts, 56, 30))
+
+    data: Data
+>data : Symbol(WithoutError.data, Decl(discriminatedUnionTypes2.ts, 57, 15))
+>Data : Symbol(Data, Decl(discriminatedUnionTypes2.ts, 56, 23))
+}
+
+type DataCarrier<Data> = WithError | WithoutError<Data>
+>DataCarrier : Symbol(DataCarrier, Decl(discriminatedUnionTypes2.ts, 59, 1))
+>Data : Symbol(Data, Decl(discriminatedUnionTypes2.ts, 61, 17))
+>WithError : Symbol(WithError, Decl(discriminatedUnionTypes2.ts, 47, 34))
+>WithoutError : Symbol(WithoutError, Decl(discriminatedUnionTypes2.ts, 54, 1))
+>Data : Symbol(Data, Decl(discriminatedUnionTypes2.ts, 61, 17))
+
+function f20<Data>(carrier: DataCarrier<Data>) {
+>f20 : Symbol(f20, Decl(discriminatedUnionTypes2.ts, 61, 55))
+>Data : Symbol(Data, Decl(discriminatedUnionTypes2.ts, 63, 13))
+>carrier : Symbol(carrier, Decl(discriminatedUnionTypes2.ts, 63, 19))
+>DataCarrier : Symbol(DataCarrier, Decl(discriminatedUnionTypes2.ts, 59, 1))
+>Data : Symbol(Data, Decl(discriminatedUnionTypes2.ts, 63, 13))
+
+    if (carrier.error === null) {
+>carrier.error : Symbol(error, Decl(discriminatedUnionTypes2.ts, 51, 21), Decl(discriminatedUnionTypes2.ts, 56, 30))
+>carrier : Symbol(carrier, Decl(discriminatedUnionTypes2.ts, 63, 19))
+>error : Symbol(error, Decl(discriminatedUnionTypes2.ts, 51, 21), Decl(discriminatedUnionTypes2.ts, 56, 30))
+
+        const error: null = carrier.error
+>error : Symbol(error, Decl(discriminatedUnionTypes2.ts, 65, 13))
+>carrier.error : Symbol(WithoutError.error, Decl(discriminatedUnionTypes2.ts, 56, 30))
+>carrier : Symbol(carrier, Decl(discriminatedUnionTypes2.ts, 63, 19))
+>error : Symbol(WithoutError.error, Decl(discriminatedUnionTypes2.ts, 56, 30))
+
+        const data: Data = carrier.data
+>data : Symbol(data, Decl(discriminatedUnionTypes2.ts, 66, 13))
+>Data : Symbol(Data, Decl(discriminatedUnionTypes2.ts, 63, 13))
+>carrier.data : Symbol(WithoutError.data, Decl(discriminatedUnionTypes2.ts, 57, 15))
+>carrier : Symbol(carrier, Decl(discriminatedUnionTypes2.ts, 63, 19))
+>data : Symbol(WithoutError.data, Decl(discriminatedUnionTypes2.ts, 57, 15))
+
+    } else {
+        const error: Error = carrier.error
+>error : Symbol(error, Decl(discriminatedUnionTypes2.ts, 68, 13))
+>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
+>carrier.error : Symbol(WithError.error, Decl(discriminatedUnionTypes2.ts, 51, 21))
+>carrier : Symbol(carrier, Decl(discriminatedUnionTypes2.ts, 63, 19))
+>error : Symbol(WithError.error, Decl(discriminatedUnionTypes2.ts, 51, 21))
+
+        const data: null = carrier.data
+>data : Symbol(data, Decl(discriminatedUnionTypes2.ts, 69, 13))
+>carrier.data : Symbol(WithError.data, Decl(discriminatedUnionTypes2.ts, 52, 16))
+>carrier : Symbol(carrier, Decl(discriminatedUnionTypes2.ts, 63, 19))
+>data : Symbol(WithError.data, Decl(discriminatedUnionTypes2.ts, 52, 16))
+    }
+}
+
diff --git a/tests/baselines/reference/discriminatedUnionTypes2.types b/tests/baselines/reference/discriminatedUnionTypes2.types
new file mode 100644
index 0000000000000..b654fc1a78d5c
--- /dev/null
+++ b/tests/baselines/reference/discriminatedUnionTypes2.types
@@ -0,0 +1,241 @@
+=== tests/cases/conformance/types/union/discriminatedUnionTypes2.ts ===
+function f10(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) {
+>f10 : (x: { kind: false; a: string; } | { kind: true; b: string; } | { kind: string; c: string; }) => void
+>x : { kind: false; a: string; } | { kind: true; b: string; } | { kind: string; c: string; }
+>kind : false
+>false : false
+>a : string
+>kind : true
+>true : true
+>b : string
+>kind : string
+>c : string
+
+    if (x.kind === false) {
+>x.kind === false : boolean
+>x.kind : string | boolean
+>x : { kind: false; a: string; } | { kind: true; b: string; } | { kind: string; c: string; }
+>kind : string | boolean
+>false : false
+
+        x.a;
+>x.a : string
+>x : { kind: false; a: string; }
+>a : string
+    }
+    else if (x.kind === true) {
+>x.kind === true : boolean
+>x.kind : string | true
+>x : { kind: true; b: string; } | { kind: string; c: string; }
+>kind : string | true
+>true : true
+
+        x.b;
+>x.b : string
+>x : { kind: true; b: string; }
+>b : string
+    }
+    else {
+        x.c;
+>x.c : string
+>x : { kind: string; c: string; }
+>c : string
+    }
+}
+
+function f11(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) {
+>f11 : (x: { kind: false; a: string; } | { kind: true; b: string; } | { kind: string; c: string; }) => void
+>x : { kind: false; a: string; } | { kind: true; b: string; } | { kind: string; c: string; }
+>kind : false
+>false : false
+>a : string
+>kind : true
+>true : true
+>b : string
+>kind : string
+>c : string
+
+    switch (x.kind) {
+>x.kind : string | boolean
+>x : { kind: false; a: string; } | { kind: true; b: string; } | { kind: string; c: string; }
+>kind : string | boolean
+
+        case false:
+>false : false
+
+            x.a;
+>x.a : string
+>x : { kind: false; a: string; }
+>a : string
+
+            break;
+        case true:
+>true : true
+
+            x.b;
+>x.b : string
+>x : { kind: true; b: string; }
+>b : string
+
+            break;
+        default:
+            x.c;
+>x.c : string
+>x : { kind: string; c: string; }
+>c : string
+    }
+}
+
+function f13(x: { a: null; b: string } | { a: string, c: number }) {
+>f13 : (x: { a: null; b: string; } | { a: string; c: number; }) => void
+>x : { a: null; b: string; } | { a: string; c: number; }
+>a : null
+>null : null
+>b : string
+>a : string
+>c : number
+
+    x = { a: null, b: "foo", c: 4};  // Error
+>x = { a: null, b: "foo", c: 4} : { a: null; b: string; c: number; }
+>x : { a: null; b: string; } | { a: string; c: number; }
+>{ a: null, b: "foo", c: 4} : { a: null; b: string; c: number; }
+>a : null
+>null : null
+>b : string
+>"foo" : "foo"
+>c : number
+>4 : 4
+}
+
+function f14<T>(x: { a: 0; b: string } | { a: T, c: number }) {
+>f14 : <T>(x: { a: 0; b: string; } | { a: T; c: number; }) => void
+>x : { a: 0; b: string; } | { a: T; c: number; }
+>a : 0
+>b : string
+>a : T
+>c : number
+
+    if (x.a === 0) {
+>x.a === 0 : boolean
+>x.a : 0 | T
+>x : { a: 0; b: string; } | { a: T; c: number; }
+>a : 0 | T
+>0 : 0
+
+        x.b;  // Error
+>x.b : any
+>x : { a: 0; b: string; } | { a: T; c: number; }
+>b : any
+    }
+}
+
+type Result<T> = { error?: undefined, value: T } | { error: Error };
+>Result : Result<T>
+>error : undefined
+>value : T
+>error : Error
+
+function f15(x: Result<number>) {
+>f15 : (x: Result<number>) => void
+>x : Result<number>
+
+    if (!x.error) {
+>!x.error : boolean
+>x.error : Error | undefined
+>x : Result<number>
+>error : Error | undefined
+
+        x.value;
+>x.value : number
+>x : { error?: undefined; value: number; }
+>value : number
+    }
+    else {
+        x.error.message;
+>x.error.message : string
+>x.error : Error
+>x : { error: Error; }
+>error : Error
+>message : string
+    }
+}
+
+f15({ value: 10 });
+>f15({ value: 10 }) : void
+>f15 : (x: Result<number>) => void
+>{ value: 10 } : { value: number; }
+>value : number
+>10 : 10
+
+f15({ error: new Error("boom") });
+>f15({ error: new Error("boom") }) : void
+>f15 : (x: Result<number>) => void
+>{ error: new Error("boom") } : { error: Error; }
+>error : Error
+>new Error("boom") : Error
+>Error : ErrorConstructor
+>"boom" : "boom"
+
+// Repro from #24193
+
+interface WithError {
+    error: Error
+>error : Error
+
+    data: null
+>data : null
+>null : null
+}
+
+interface WithoutError<Data> {
+    error: null
+>error : null
+>null : null
+
+    data: Data
+>data : Data
+}
+
+type DataCarrier<Data> = WithError | WithoutError<Data>
+>DataCarrier : DataCarrier<Data>
+
+function f20<Data>(carrier: DataCarrier<Data>) {
+>f20 : <Data>(carrier: DataCarrier<Data>) => void
+>carrier : DataCarrier<Data>
+
+    if (carrier.error === null) {
+>carrier.error === null : boolean
+>carrier.error : Error | null
+>carrier : DataCarrier<Data>
+>error : Error | null
+>null : null
+
+        const error: null = carrier.error
+>error : null
+>null : null
+>carrier.error : null
+>carrier : WithoutError<Data>
+>error : null
+
+        const data: Data = carrier.data
+>data : Data
+>carrier.data : Data
+>carrier : WithoutError<Data>
+>data : Data
+
+    } else {
+        const error: Error = carrier.error
+>error : Error
+>carrier.error : Error
+>carrier : WithError
+>error : Error
+
+        const data: null = carrier.data
+>data : null
+>null : null
+>carrier.data : null
+>carrier : WithError
+>data : null
+    }
+}
+
diff --git a/tests/baselines/reference/objectLiteralNormalization.errors.txt b/tests/baselines/reference/objectLiteralNormalization.errors.txt
index 3cdda885277eb..2a09dd3b4df50 100644
--- a/tests/baselines/reference/objectLiteralNormalization.errors.txt
+++ b/tests/baselines/reference/objectLiteralNormalization.errors.txt
@@ -10,9 +10,8 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts
     Types of property 'a' are incompatible.
       Type 'string' is not assignable to type 'undefined'.
 tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts(18,1): error TS2322: Type '{ a: number; }' is not assignable to type '{ a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; }'.
-  Type '{ a: number; }' is not assignable to type '{ a?: undefined; b?: undefined; }'.
-    Types of property 'a' are incompatible.
-      Type 'number' is not assignable to type 'undefined'.
+  Type '{ a: number; }' is not assignable to type '{ a: number; b: number; }'.
+    Property 'b' is missing in type '{ a: number; }'.
 
 
 ==== tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts (5 errors) ====
@@ -52,9 +51,8 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts
     a2 = { a: 1 };  // Error
     ~~
 !!! error TS2322: Type '{ a: number; }' is not assignable to type '{ a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; }'.
-!!! error TS2322:   Type '{ a: number; }' is not assignable to type '{ a?: undefined; b?: undefined; }'.
-!!! error TS2322:     Types of property 'a' are incompatible.
-!!! error TS2322:       Type 'number' is not assignable to type 'undefined'.
+!!! error TS2322:   Type '{ a: number; }' is not assignable to type '{ a: number; b: number; }'.
+!!! error TS2322:     Property 'b' is missing in type '{ a: number; }'.
     
     // Object literals containing spreads are not normalized
     declare let b1: { a: string, b: string } | { b: string, c: string };
diff --git a/tests/baselines/reference/recursiveMappedTypes.errors.txt b/tests/baselines/reference/recursiveMappedTypes.errors.txt
index 8279f4f60a65a..b702cf7e3169d 100644
--- a/tests/baselines/reference/recursiveMappedTypes.errors.txt
+++ b/tests/baselines/reference/recursiveMappedTypes.errors.txt
@@ -31,4 +31,14 @@ tests/cases/conformance/types/mapped/recursiveMappedTypes.ts(12,11): error TS231
         [K in keyof Recurse1]: Recurse1[K]
               ~~~~~~~~~~~~~~
 !!! error TS2313: Type parameter 'K' has a circular constraint.
-    }
\ No newline at end of file
+    }
+    
+    // Repro from #27881
+    
+    export type Circular<T> = {[P in keyof T]: Circular<T>};
+    type tup = [number, number, number, number];
+    
+    function foo(arg: Circular<tup>): tup {
+      return arg;
+    }
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/recursiveMappedTypes.js b/tests/baselines/reference/recursiveMappedTypes.js
index 5061070866428..612c9d3fca4e8 100644
--- a/tests/baselines/reference/recursiveMappedTypes.js
+++ b/tests/baselines/reference/recursiveMappedTypes.js
@@ -11,19 +11,28 @@ type Recurse1 = {
 
 type Recurse2 = {
     [K in keyof Recurse1]: Recurse1[K]
-}
+}
+
+// Repro from #27881
+
+export type Circular<T> = {[P in keyof T]: Circular<T>};
+type tup = [number, number, number, number];
+
+function foo(arg: Circular<tup>): tup {
+  return arg;
+}
+
 
 //// [recursiveMappedTypes.js]
+"use strict";
 // Recursive mapped types simply appear empty
+exports.__esModule = true;
+function foo(arg) {
+    return arg;
+}
 
 
 //// [recursiveMappedTypes.d.ts]
-declare type Recurse = {
-    [K in keyof Recurse]: Recurse[K];
-};
-declare type Recurse1 = {
-    [K in keyof Recurse2]: Recurse2[K];
-};
-declare type Recurse2 = {
-    [K in keyof Recurse1]: Recurse1[K];
+export declare type Circular<T> = {
+    [P in keyof T]: Circular<T>;
 };
diff --git a/tests/baselines/reference/recursiveMappedTypes.symbols b/tests/baselines/reference/recursiveMappedTypes.symbols
index 20ebbedc00abb..7c0e2ffaa2341 100644
--- a/tests/baselines/reference/recursiveMappedTypes.symbols
+++ b/tests/baselines/reference/recursiveMappedTypes.symbols
@@ -30,3 +30,28 @@ type Recurse2 = {
 >Recurse1 : Symbol(Recurse1, Decl(recursiveMappedTypes.ts, 4, 1))
 >K : Symbol(K, Decl(recursiveMappedTypes.ts, 11, 5))
 }
+
+// Repro from #27881
+
+export type Circular<T> = {[P in keyof T]: Circular<T>};
+>Circular : Symbol(Circular, Decl(recursiveMappedTypes.ts, 12, 1))
+>T : Symbol(T, Decl(recursiveMappedTypes.ts, 16, 21))
+>P : Symbol(P, Decl(recursiveMappedTypes.ts, 16, 28))
+>T : Symbol(T, Decl(recursiveMappedTypes.ts, 16, 21))
+>Circular : Symbol(Circular, Decl(recursiveMappedTypes.ts, 12, 1))
+>T : Symbol(T, Decl(recursiveMappedTypes.ts, 16, 21))
+
+type tup = [number, number, number, number];
+>tup : Symbol(tup, Decl(recursiveMappedTypes.ts, 16, 56))
+
+function foo(arg: Circular<tup>): tup {
+>foo : Symbol(foo, Decl(recursiveMappedTypes.ts, 17, 44))
+>arg : Symbol(arg, Decl(recursiveMappedTypes.ts, 19, 13))
+>Circular : Symbol(Circular, Decl(recursiveMappedTypes.ts, 12, 1))
+>tup : Symbol(tup, Decl(recursiveMappedTypes.ts, 16, 56))
+>tup : Symbol(tup, Decl(recursiveMappedTypes.ts, 16, 56))
+
+  return arg;
+>arg : Symbol(arg, Decl(recursiveMappedTypes.ts, 19, 13))
+}
+
diff --git a/tests/baselines/reference/recursiveMappedTypes.types b/tests/baselines/reference/recursiveMappedTypes.types
index aae3280b60580..5741f711e9d6f 100644
--- a/tests/baselines/reference/recursiveMappedTypes.types
+++ b/tests/baselines/reference/recursiveMappedTypes.types
@@ -18,3 +18,20 @@ type Recurse2 = {
 
     [K in keyof Recurse1]: Recurse1[K]
 }
+
+// Repro from #27881
+
+export type Circular<T> = {[P in keyof T]: Circular<T>};
+>Circular : Circular<T>
+
+type tup = [number, number, number, number];
+>tup : [number, number, number, number]
+
+function foo(arg: Circular<tup>): tup {
+>foo : (arg: [any, any, any, any]) => [number, number, number, number]
+>arg : [any, any, any, any]
+
+  return arg;
+>arg : [any, any, any, any]
+}
+
diff --git a/tests/cases/conformance/types/mapped/recursiveMappedTypes.ts b/tests/cases/conformance/types/mapped/recursiveMappedTypes.ts
index 7a78ad9dc4a62..188efa2f51a54 100644
--- a/tests/cases/conformance/types/mapped/recursiveMappedTypes.ts
+++ b/tests/cases/conformance/types/mapped/recursiveMappedTypes.ts
@@ -12,4 +12,13 @@ type Recurse1 = {
 
 type Recurse2 = {
     [K in keyof Recurse1]: Recurse1[K]
-}
\ No newline at end of file
+}
+
+// Repro from #27881
+
+export type Circular<T> = {[P in keyof T]: Circular<T>};
+type tup = [number, number, number, number];
+
+function foo(arg: Circular<tup>): tup {
+  return arg;
+}
diff --git a/tests/cases/conformance/types/union/discriminatedUnionTypes2.ts b/tests/cases/conformance/types/union/discriminatedUnionTypes2.ts
new file mode 100644
index 0000000000000..789bc263c7ebc
--- /dev/null
+++ b/tests/cases/conformance/types/union/discriminatedUnionTypes2.ts
@@ -0,0 +1,74 @@
+// @strict: true
+
+function f10(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) {
+    if (x.kind === false) {
+        x.a;
+    }
+    else if (x.kind === true) {
+        x.b;
+    }
+    else {
+        x.c;
+    }
+}
+
+function f11(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) {
+    switch (x.kind) {
+        case false:
+            x.a;
+            break;
+        case true:
+            x.b;
+            break;
+        default:
+            x.c;
+    }
+}
+
+function f13(x: { a: null; b: string } | { a: string, c: number }) {
+    x = { a: null, b: "foo", c: 4};  // Error
+}
+
+function f14<T>(x: { a: 0; b: string } | { a: T, c: number }) {
+    if (x.a === 0) {
+        x.b;  // Error
+    }
+}
+
+type Result<T> = { error?: undefined, value: T } | { error: Error };
+
+function f15(x: Result<number>) {
+    if (!x.error) {
+        x.value;
+    }
+    else {
+        x.error.message;
+    }
+}
+
+f15({ value: 10 });
+f15({ error: new Error("boom") });
+
+// Repro from #24193
+
+interface WithError {
+    error: Error
+    data: null
+}
+
+interface WithoutError<Data> {
+    error: null
+    data: Data
+}
+
+type DataCarrier<Data> = WithError | WithoutError<Data>
+
+function f20<Data>(carrier: DataCarrier<Data>) {
+    if (carrier.error === null) {
+        const error: null = carrier.error
+        const data: Data = carrier.data
+    } else {
+        const error: Error = carrier.error
+        const data: null = carrier.data
+    }
+}