diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 963d2e77c1b5c..756a2b2d3b191 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -12444,6 +12444,10 @@ namespace ts {
             }
             const prop = getPropertyOfType(apparentType, right.text);
             if (!prop) {
+                const stringIndexType = getIndexTypeOfType(apparentType, IndexKind.String);
+                if (stringIndexType) {
+                    return stringIndexType;
+                }
                 if (right.text && !checkAndReportErrorForExtendingInterface(node)) {
                     reportNonexistentProperty(right, type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType ? apparentType : type);
                 }
diff --git a/tests/baselines/reference/objectRest.js b/tests/baselines/reference/objectRest.js
index 59eb11542c070..3576ffb286cde 100644
--- a/tests/baselines/reference/objectRest.js
+++ b/tests/baselines/reference/objectRest.js
@@ -44,7 +44,7 @@ let computed2 = 'a';
 var { [computed]: stillNotGreat, [computed2]: soSo,  ...o } = o;
 ({ [computed]: stillNotGreat, [computed2]: soSo, ...o } = o);
 
-var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes'];
+var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes;
 
 
 //// [objectRest.js]
@@ -89,6 +89,6 @@ var _g = computed, stillNotGreat = o[_g], _h = computed2, soSo = o[_h], o = __re
 (_j = computed, stillNotGreat = o[_j], _k = computed2, soSo = o[_k], o = __rest(o, [typeof _j === "symbol" ? _j : _j + "", typeof _k === "symbol" ? _k : _k + ""]));
 var noContextualType = (_a) => {
     var { aNumber = 12 } = _a, notEmptyObject = __rest(_a, ["aNumber"]);
-    return aNumber + notEmptyObject['anythingGoes'];
+    return aNumber + notEmptyObject.anythingGoes;
 };
 var _d, _f, _j, _k;
diff --git a/tests/baselines/reference/objectRest.symbols b/tests/baselines/reference/objectRest.symbols
index 2992220d8b2bc..41226bd99fc88 100644
--- a/tests/baselines/reference/objectRest.symbols
+++ b/tests/baselines/reference/objectRest.symbols
@@ -191,7 +191,7 @@ var { [computed]: stillNotGreat, [computed2]: soSo,  ...o } = o;
 >o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 42, 51))
 >o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 42, 51))
 
-var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes'];
+var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes;
 >noContextualType : Symbol(noContextualType, Decl(objectRest.ts, 45, 3))
 >aNumber : Symbol(aNumber, Decl(objectRest.ts, 45, 25))
 >notEmptyObject : Symbol(notEmptyObject, Decl(objectRest.ts, 45, 39))
diff --git a/tests/baselines/reference/objectRest.types b/tests/baselines/reference/objectRest.types
index 5347f09f5a350..2fff9a3c72983 100644
--- a/tests/baselines/reference/objectRest.types
+++ b/tests/baselines/reference/objectRest.types
@@ -217,15 +217,15 @@ var { [computed]: stillNotGreat, [computed2]: soSo,  ...o } = o;
 >o : { a: number; b: string; }
 >o : { a: number; b: string; }
 
-var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes'];
+var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes;
 >noContextualType : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => any
->({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes'] : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => any
+>({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes : ({aNumber, ...notEmptyObject}: { [x: string]: any; aNumber?: number; }) => any
 >aNumber : number
 >12 : 12
 >notEmptyObject : { [x: string]: any; }
->aNumber + notEmptyObject['anythingGoes'] : any
+>aNumber + notEmptyObject.anythingGoes : any
 >aNumber : number
->notEmptyObject['anythingGoes'] : any
+>notEmptyObject.anythingGoes : any
 >notEmptyObject : { [x: string]: any; }
->'anythingGoes' : "anythingGoes"
+>anythingGoes : any
 
diff --git a/tests/baselines/reference/objectRestNegative.errors.txt b/tests/baselines/reference/objectRestNegative.errors.txt
index 6e65af4bdc138..56de8aaccb67f 100644
--- a/tests/baselines/reference/objectRestNegative.errors.txt
+++ b/tests/baselines/reference/objectRestNegative.errors.txt
@@ -7,10 +7,9 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(11,30): error TS7008: M
 tests/cases/conformance/types/rest/objectRestNegative.ts(11,33): error TS7008: Member 'y' implicitly has an 'any' type.
 tests/cases/conformance/types/rest/objectRestNegative.ts(12,17): error TS2700: Rest types may only be created from object types.
 tests/cases/conformance/types/rest/objectRestNegative.ts(17,9): error TS2701: The target of an object rest assignment must be a variable or a property access.
-tests/cases/conformance/types/rest/objectRestNegative.ts(19,90): error TS2339: Property 'anythingGoes' does not exist on type '{ [x: string]: any; }'.
 
 
-==== tests/cases/conformance/types/rest/objectRestNegative.ts (8 errors) ====
+==== tests/cases/conformance/types/rest/objectRestNegative.ts (7 errors) ====
     let o = { a: 1, b: 'no' };
     var { ...mustBeLast, a } = o;
              ~~~~~~~~~~
@@ -44,8 +43,4 @@ tests/cases/conformance/types/rest/objectRestNegative.ts(19,90): error TS2339: P
     ({a, ...rest.b + rest.b} = o);
             ~~~~~~~~~~~~~~~
 !!! error TS2701: The target of an object rest assignment must be a variable or a property access.
-    
-    var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes;
-                                                                                             ~~~~~~~~~~~~
-!!! error TS2339: Property 'anythingGoes' does not exist on type '{ [x: string]: any; }'.
     
\ No newline at end of file
diff --git a/tests/baselines/reference/objectRestNegative.js b/tests/baselines/reference/objectRestNegative.js
index 19559e865f293..915e0a0e86732 100644
--- a/tests/baselines/reference/objectRestNegative.js
+++ b/tests/baselines/reference/objectRestNegative.js
@@ -16,8 +16,6 @@ function generic<T extends { x, y }>(t: T) {
 
 let rest: { b: string }
 ({a, ...rest.b + rest.b} = o);
-
-var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes;
 
 
 //// [objectRestNegative.js]
@@ -44,7 +42,3 @@ function generic(t) {
 }
 var rest;
 (a = o.a, o, rest.b + rest.b = __rest(o, ["a"]));
-var noContextualType = function (_a) {
-    var _b = _a.aNumber, aNumber = _b === void 0 ? 12 : _b, notEmptyObject = __rest(_a, ["aNumber"]);
-    return aNumber + notEmptyObject.anythingGoes;
-};
diff --git a/tests/baselines/reference/propertyAccessStringIndexSignature.errors.txt b/tests/baselines/reference/propertyAccessStringIndexSignature.errors.txt
new file mode 100644
index 0000000000000..d376551d91d15
--- /dev/null
+++ b/tests/baselines/reference/propertyAccessStringIndexSignature.errors.txt
@@ -0,0 +1,18 @@
+tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignature.ts(10,7): error TS2339: Property 'nope' does not exist on type 'Empty'.
+
+
+==== tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignature.ts (1 errors) ====
+    interface Flags { [name: string]: boolean };
+    let flags: Flags;
+    flags.b;
+    flags.f;
+    flags.isNotNecessarilyNeverFalse;
+    flags['this is fine'];
+    
+    interface Empty { }
+    let empty: Empty;
+    empty.nope;
+          ~~~~
+!!! error TS2339: Property 'nope' does not exist on type 'Empty'.
+    empty["that's ok"];
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/propertyAccessStringIndexSignature.js b/tests/baselines/reference/propertyAccessStringIndexSignature.js
new file mode 100644
index 0000000000000..d37a8bfea0e61
--- /dev/null
+++ b/tests/baselines/reference/propertyAccessStringIndexSignature.js
@@ -0,0 +1,24 @@
+//// [propertyAccessStringIndexSignature.ts]
+interface Flags { [name: string]: boolean };
+let flags: Flags;
+flags.b;
+flags.f;
+flags.isNotNecessarilyNeverFalse;
+flags['this is fine'];
+
+interface Empty { }
+let empty: Empty;
+empty.nope;
+empty["that's ok"];
+
+
+//// [propertyAccessStringIndexSignature.js]
+;
+var flags;
+flags.b;
+flags.f;
+flags.isNotNecessarilyNeverFalse;
+flags['this is fine'];
+var empty;
+empty.nope;
+empty["that's ok"];
diff --git a/tests/baselines/reference/propertyAccessStringIndexSignatureNoImplicitAny.errors.txt b/tests/baselines/reference/propertyAccessStringIndexSignatureNoImplicitAny.errors.txt
new file mode 100644
index 0000000000000..d5fda18109687
--- /dev/null
+++ b/tests/baselines/reference/propertyAccessStringIndexSignatureNoImplicitAny.errors.txt
@@ -0,0 +1,21 @@
+tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignatureNoImplicitAny.ts(10,7): error TS2339: Property 'nope' does not exist on type 'Empty'.
+tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignatureNoImplicitAny.ts(11,1): error TS7017: Element implicitly has an 'any' type because type 'Empty' has no index signature.
+
+
+==== tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignatureNoImplicitAny.ts (2 errors) ====
+    interface Flags { [name: string]: boolean }
+    let flags: Flags;
+    flags.b;
+    flags.f;
+    flags.isNotNecessarilyNeverFalse;
+    flags['this is fine'];
+    
+    interface Empty { }
+    let empty: Empty;
+    empty.nope;
+          ~~~~
+!!! error TS2339: Property 'nope' does not exist on type 'Empty'.
+    empty["not allowed either"];
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS7017: Element implicitly has an 'any' type because type 'Empty' has no index signature.
+    
\ No newline at end of file
diff --git a/tests/baselines/reference/propertyAccessStringIndexSignatureNoImplicitAny.js b/tests/baselines/reference/propertyAccessStringIndexSignatureNoImplicitAny.js
new file mode 100644
index 0000000000000..3c2abcc182b41
--- /dev/null
+++ b/tests/baselines/reference/propertyAccessStringIndexSignatureNoImplicitAny.js
@@ -0,0 +1,23 @@
+//// [propertyAccessStringIndexSignatureNoImplicitAny.ts]
+interface Flags { [name: string]: boolean }
+let flags: Flags;
+flags.b;
+flags.f;
+flags.isNotNecessarilyNeverFalse;
+flags['this is fine'];
+
+interface Empty { }
+let empty: Empty;
+empty.nope;
+empty["not allowed either"];
+
+
+//// [propertyAccessStringIndexSignatureNoImplicitAny.js]
+var flags;
+flags.b;
+flags.f;
+flags.isNotNecessarilyNeverFalse;
+flags['this is fine'];
+var empty;
+empty.nope;
+empty["not allowed either"];
diff --git a/tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignature.ts b/tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignature.ts
new file mode 100644
index 0000000000000..7faf758bc9f60
--- /dev/null
+++ b/tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignature.ts
@@ -0,0 +1,11 @@
+interface Flags { [name: string]: boolean };
+let flags: Flags;
+flags.b;
+flags.f;
+flags.isNotNecessarilyNeverFalse;
+flags['this is fine'];
+
+interface Empty { }
+let empty: Empty;
+empty.nope;
+empty["that's ok"];
diff --git a/tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignatureNoImplicitAny.ts b/tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignatureNoImplicitAny.ts
new file mode 100644
index 0000000000000..bfb64c6098ac5
--- /dev/null
+++ b/tests/cases/conformance/expressions/propertyAccess/propertyAccessStringIndexSignatureNoImplicitAny.ts
@@ -0,0 +1,12 @@
+// @noImplicitAny: true
+interface Flags { [name: string]: boolean }
+let flags: Flags;
+flags.b;
+flags.f;
+flags.isNotNecessarilyNeverFalse;
+flags['this is fine'];
+
+interface Empty { }
+let empty: Empty;
+empty.nope;
+empty["not allowed either"];
diff --git a/tests/cases/conformance/types/rest/objectRest.ts b/tests/cases/conformance/types/rest/objectRest.ts
index 77f0fca1ed772..7403340c7cb4f 100644
--- a/tests/cases/conformance/types/rest/objectRest.ts
+++ b/tests/cases/conformance/types/rest/objectRest.ts
@@ -44,4 +44,4 @@ let computed2 = 'a';
 var { [computed]: stillNotGreat, [computed2]: soSo,  ...o } = o;
 ({ [computed]: stillNotGreat, [computed2]: soSo, ...o } = o);
 
-var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes'];
+var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes;
diff --git a/tests/cases/conformance/types/rest/objectRestNegative.ts b/tests/cases/conformance/types/rest/objectRestNegative.ts
index 4f4667fe65a16..13d214e453de4 100644
--- a/tests/cases/conformance/types/rest/objectRestNegative.ts
+++ b/tests/cases/conformance/types/rest/objectRestNegative.ts
@@ -16,5 +16,3 @@ function generic<T extends { x, y }>(t: T) {
 
 let rest: { b: string }
 ({a, ...rest.b + rest.b} = o);
-
-var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject.anythingGoes;