diff --git a/src/generators/Generator.ts b/src/generators/Generator.ts
index 5bbf2e17f1..0b9b2eee9a 100644
--- a/src/generators/Generator.ts
+++ b/src/generators/Generator.ts
@@ -93,6 +93,7 @@ export default class Generator {
 	helpers: Set<string>;
 	components: Set<string>;
 	events: Set<string>;
+	methods: Set<string>;
 	transitions: Set<string>;
 	actions: Set<string>;
 	importedComponents: Map<string, string>;
@@ -141,6 +142,7 @@ export default class Generator {
 		this.helpers = new Set();
 		this.components = new Set();
 		this.events = new Set();
+		this.methods = new Set();
 		this.transitions = new Set();
 		this.actions = new Set();
 		this.importedComponents = new Map();
@@ -419,6 +421,7 @@ export default class Generator {
 			code,
 			source,
 			computations,
+			methods,
 			templateProperties,
 			imports
 		} = this;
@@ -608,6 +611,10 @@ export default class Generator {
 
 				if (templateProperties.methods && dom) {
 					addDeclaration('methods', templateProperties.methods.value);
+
+					templateProperties.methods.value.properties.forEach(prop => {
+						this.methods.add(prop.key.name);
+					});
 				}
 
 				if (templateProperties.namespace) {
diff --git a/src/generators/nodes/Element.ts b/src/generators/nodes/Element.ts
index 87c44d05de..0bc180e8d1 100644
--- a/src/generators/nodes/Element.ts
+++ b/src/generators/nodes/Element.ts
@@ -519,10 +519,19 @@ export default class Element extends Node {
 				if (!validCalleeObjects.has(flattened.name)) {
 					// allow event.stopPropagation(), this.select() etc
 					// TODO verify that it's a valid callee (i.e. built-in or declared method)
-					generator.code.prependRight(
-						attribute.expression.start,
-						`${block.alias('component')}.`
-					);
+					if (flattened.name[0] === '$' && !generator.methods.has(flattened.name)) {
+						generator.code.overwrite(
+							attribute.expression.start,
+							attribute.expression.start + 1,
+							`${block.alias('component')}.store.`
+						);
+					} else {
+						generator.code.prependRight(
+							attribute.expression.start,
+							`${block.alias('component')}.`
+						);
+					}
+
 					if (shouldHoist) eventHandlerUsesComponent = true; // this feels a bit hacky but it works!
 				}
 
diff --git a/src/validate/html/validateEventHandler.ts b/src/validate/html/validateEventHandler.ts
index a5f4d8edeb..1b33b3e786 100644
--- a/src/validate/html/validateEventHandler.ts
+++ b/src/validate/html/validateEventHandler.ts
@@ -24,7 +24,7 @@ export default function validateEventHandlerCallee(
 
 	const { name } = flattenReference(callee);
 
-	if (validCalleeObjects.has(name) || name === 'options' || name === 'store') return;
+	if (validCalleeObjects.has(name) || name === 'options') return;
 
 	if (name === 'refs') {
 		refCallees.push(callee);
@@ -34,21 +34,30 @@ export default function validateEventHandlerCallee(
 	if (
 		(callee.type === 'Identifier' && validBuiltins.has(callee.name)) ||
 		validator.methods.has(callee.name)
-	)
+	) {
 		return;
+	}
 
-	const validCallees = ['this.*', 'event.*', 'options.*', 'console.*', 'store.*'].concat(
+	if (name[0] === '$') {
+		// assume it's a store method
+		return;
+	}
+
+	const validCallees = ['this.*', 'event.*', 'options.*', 'console.*'].concat(
 		Array.from(validBuiltins),
 		Array.from(validator.methods.keys())
 	);
 
-	let message = `'${validator.source.slice(
-		callee.start,
-		callee.end
-	)}' is an invalid callee (should be one of ${list(validCallees)})`;
+	let message = `'${validator.source.slice(callee.start, callee.end)}' is an invalid callee ` ;
+
+	if (name === 'store') {
+		message += `(did you mean '$${validator.source.slice(callee.start + 6, callee.end)}(...)'?)`;
+	} else {
+		message += `(should be one of ${list(validCallees)})`;
 
-	if (callee.type === 'Identifier' && validator.helpers.has(callee.name)) {
-		message += `. '${callee.name}' exists on 'helpers', did you put it in the wrong place?`;
+		if (callee.type === 'Identifier' && validator.helpers.has(callee.name)) {
+			message += `. '${callee.name}' exists on 'helpers', did you put it in the wrong place?`;
+		}
 	}
 
 	validator.warn(attribute.expression, {
diff --git a/test/runtime/samples/store-event/NameInput.html b/test/runtime/samples/store-event/NameInput.html
index ecd95d0364..d1d31bf64e 100644
--- a/test/runtime/samples/store-event/NameInput.html
+++ b/test/runtime/samples/store-event/NameInput.html
@@ -1 +1 @@
-<input on:input='store.setName(this.value)'>
\ No newline at end of file
+<input on:input='$setName(this.value)'>
\ No newline at end of file
diff --git a/test/validator/samples/method-nonexistent-helper/warnings.json b/test/validator/samples/method-nonexistent-helper/warnings.json
index e1575d2bbd..b463045538 100644
--- a/test/validator/samples/method-nonexistent-helper/warnings.json
+++ b/test/validator/samples/method-nonexistent-helper/warnings.json
@@ -1,6 +1,6 @@
 [{
 	"code": "invalid-callee",
-	"message": "'foo' is an invalid callee (should be one of this.*, event.*, options.*, console.*, store.*, set, fire, destroy or bar). 'foo' exists on 'helpers', did you put it in the wrong place?",
+	"message": "'foo' is an invalid callee (should be one of this.*, event.*, options.*, console.*, set, fire, destroy or bar). 'foo' exists on 'helpers', did you put it in the wrong place?",
 	"pos": 18,
 	"start": {
 		"line": 1,
diff --git a/test/validator/samples/method-nonexistent/warnings.json b/test/validator/samples/method-nonexistent/warnings.json
index 324c9bd0d5..3ad9ee8734 100644
--- a/test/validator/samples/method-nonexistent/warnings.json
+++ b/test/validator/samples/method-nonexistent/warnings.json
@@ -1,6 +1,6 @@
 [{
 	"code": "invalid-callee",
-	"message": "'foo' is an invalid callee (should be one of this.*, event.*, options.*, console.*, store.*, set, fire, destroy or bar)",
+	"message": "'foo' is an invalid callee (should be one of this.*, event.*, options.*, console.*, set, fire, destroy or bar)",
 	"pos": 18,
 	"start": {
 		"line": 1,
diff --git a/test/validator/samples/store-invalid-callee/input.html b/test/validator/samples/store-invalid-callee/input.html
new file mode 100644
index 0000000000..2184dab288
--- /dev/null
+++ b/test/validator/samples/store-invalid-callee/input.html
@@ -0,0 +1 @@
+<button on:click="store.set({ foo: 'bar' })">click me</button>
\ No newline at end of file
diff --git a/test/validator/samples/store-invalid-callee/warnings.json b/test/validator/samples/store-invalid-callee/warnings.json
new file mode 100644
index 0000000000..31e7982c71
--- /dev/null
+++ b/test/validator/samples/store-invalid-callee/warnings.json
@@ -0,0 +1,15 @@
+[{
+	"code": "invalid-callee",
+	"message": "'store.set' is an invalid callee (did you mean '$set(...)'?)",
+	"pos": 18,
+	"start": {
+		"line": 1,
+		"column": 18,
+		"character": 18
+	},
+	"end": {
+		"line": 1,
+		"column": 43,
+		"character": 43
+	}
+}]
\ No newline at end of file
diff --git a/test/validator/samples/window-event-invalid/warnings.json b/test/validator/samples/window-event-invalid/warnings.json
index e88f3839f3..1d20c8fac9 100644
--- a/test/validator/samples/window-event-invalid/warnings.json
+++ b/test/validator/samples/window-event-invalid/warnings.json
@@ -1,6 +1,6 @@
 [{
 	"code": "invalid-callee",
-	"message": "'resize' is an invalid callee (should be one of this.*, event.*, options.*, console.*, store.*, set, fire or destroy)",
+	"message": "'resize' is an invalid callee (should be one of this.*, event.*, options.*, console.*, set, fire or destroy)",
 	"start": {
 		"line": 1,
 		"column": 26,