diff --git a/include/sway/config.h b/include/sway/config.h
index 045359ca..eecdde3a 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -397,6 +397,8 @@ struct seat_attachment_config *seat_config_get_attachment(
 void apply_seat_config(struct seat_config *seat);
 
 int output_name_cmp(const void *item, const void *data);
+void output_get_identifier(char *identifier, size_t len,
+	struct sway_output *output);
 struct output_config *new_output_config(const char *name);
 void merge_output_config(struct output_config *dst, struct output_config *src);
 void apply_output_config(struct output_config *oc, swayc_t *output);
diff --git a/sway/commands/output.c b/sway/commands/output.c
index 8cc74bcc..8c0fa63c 100644
--- a/sway/commands/output.c
+++ b/sway/commands/output.c
@@ -231,8 +231,8 @@ static struct cmd_results *cmd_output_background(struct output_config *output,
 }
 
 struct cmd_results *cmd_output(int argc, char **argv) {
-	struct cmd_results *error = NULL;
-	if ((error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1))) {
+	struct cmd_results *error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1);
+	if (error != NULL) {
 		return error;
 	}
 
@@ -275,11 +275,11 @@ struct cmd_results *cmd_output(int argc, char **argv) {
 
 	int i = list_seq_find(config->output_configs, output_name_cmp, output->name);
 	if (i >= 0) {
-		// merge existing config
-		struct output_config *oc = config->output_configs->items[i];
-		merge_output_config(oc, output);
+		// Merge existing config
+		struct output_config *current = config->output_configs->items[i];
+		merge_output_config(current, output);
 		free_output_config(output);
-		output = oc;
+		output = current;
 	} else {
 		list_add(config->output_configs, output);
 	}
@@ -290,22 +290,26 @@ struct cmd_results *cmd_output(int argc, char **argv) {
 		output->refresh_rate, output->x, output->y, output->scale,
 		output->transform, output->background, output->background_option);
 
-	if (output->name) {
-		// Try to find the output container and apply configuration now. If
-		// this is during startup then there will be no container and config
-		// will be applied during normal "new output" event from wlroots.
-		swayc_t *cont = NULL;
-		for (int i = 0; i < root_container.children->length; ++i) {
-			cont = root_container.children->items[i];
-			if (cont->name && ((strcmp(cont->name, output->name) == 0) ||
-					(strcmp(output->name, "*") == 0))) {
-				apply_output_config(output, cont);
+	// Try to find the output container and apply configuration now. If
+	// this is during startup then there will be no container and config
+	// will be applied during normal "new output" event from wlroots.
+	char identifier[128];
+	bool all = strcmp(output->name, "*") == 0;
+	for (int i = 0; i < root_container.children->length; ++i) {
+		swayc_t *cont = root_container.children->items[i];
+		if (cont->type != C_OUTPUT) {
+			continue;
+		}
 
-				if (strcmp(output->name, "*") != 0) {
-					// Stop looking if the output config isn't applicable to all
-					// outputs
-					break;
-				}
+		output_get_identifier(identifier, sizeof(identifier), cont->sway_output);
+		if (all || strcmp(cont->name, output->name) == 0 ||
+				strcmp(identifier, output->name) == 0) {
+			apply_output_config(output, cont);
+
+			if (!all) {
+				// Stop looking if the output config isn't applicable to all
+				// outputs
+				break;
 			}
 		}
 	}
diff --git a/sway/config/output.c b/sway/config/output.c
index f336c949..e798a20e 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -1,4 +1,5 @@
 #define _XOPEN_SOURCE 700
+#include <stdbool.h>
 #include <string.h>
 #include <assert.h>
 #include <wlr/types/wlr_output.h>
@@ -14,6 +15,13 @@ int output_name_cmp(const void *item, const void *data) {
 	return strcmp(output->name, name);
 }
 
+void output_get_identifier(char *identifier, size_t len,
+		struct sway_output *output) {
+	struct wlr_output *wlr_output = output->wlr_output;
+	snprintf(identifier, len, "%s %s %s", wlr_output->make, wlr_output->model,
+		wlr_output->serial);
+}
+
 struct output_config *new_output_config(const char *name) {
 	struct output_config *oc = calloc(1, sizeof(struct output_config));
 	if (oc == NULL) {
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 6f2a3abf..c5574275 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -49,16 +49,49 @@ static swayc_t *new_swayc(enum swayc_types type) {
 	return c;
 }
 
+static void free_swayc(swayc_t *cont) {
+	if (!sway_assert(cont, "free_swayc passed NULL")) {
+		return;
+	}
+
+	wl_signal_emit(&cont->events.destroy, cont);
+
+	if (cont->children) {
+		// remove children until there are no more, free_swayc calls
+		// remove_child, which removes child from this container
+		while (cont->children->length) {
+			free_swayc(cont->children->items[0]);
+		}
+		list_free(cont->children);
+	}
+	if (cont->marks) {
+		list_foreach(cont->marks, free);
+		list_free(cont->marks);
+	}
+	if (cont->parent) {
+		remove_child(cont);
+	}
+	if (cont->name) {
+		free(cont->name);
+	}
+	free(cont);
+}
+
 swayc_t *new_output(struct sway_output *sway_output) {
 	struct wlr_box size;
 	wlr_output_effective_resolution(sway_output->wlr_output, &size.width,
 		&size.height);
+
 	const char *name = sway_output->wlr_output->name;
+	char identifier[128];
+	output_get_identifier(identifier, sizeof(identifier), sway_output);
 
 	struct output_config *oc = NULL, *all = NULL;
 	for (int i = 0; i < config->output_configs->length; ++i) {
 		struct output_config *cur = config->output_configs->items[i];
-		if (strcasecmp(name, cur->name) == 0) {
+
+		if (strcasecmp(name, cur->name) == 0 ||
+				strcasecmp(identifier, cur->name) == 0) {
 			sway_log(L_DEBUG, "Matched output config for %s", name);
 			oc = cur;
 		}
@@ -74,13 +107,18 @@ swayc_t *new_output(struct sway_output *sway_output) {
 	if (!oc) {
 		oc = all;
 	}
+
 	if (oc && !oc->enabled) {
 		return NULL;
 	}
 
 	swayc_t *output = new_swayc(C_OUTPUT);
 	output->sway_output = sway_output;
-	output->name = name ? strdup(name) : NULL;
+	output->name = strdup(name);
+	if (output->name == NULL) {
+		free_swayc(output);
+		return NULL;
+	}
 
 	apply_output_config(oc, output);
 
@@ -140,34 +178,6 @@ swayc_t *new_view(swayc_t *sibling, struct sway_view *sway_view) {
 	return swayc;
 }
 
-static void free_swayc(swayc_t *cont) {
-	if (!sway_assert(cont, "free_swayc passed NULL")) {
-		return;
-	}
-
-	wl_signal_emit(&cont->events.destroy, cont);
-
-	if (cont->children) {
-		// remove children until there are no more, free_swayc calls
-		// remove_child, which removes child from this container
-		while (cont->children->length) {
-			free_swayc(cont->children->items[0]);
-		}
-		list_free(cont->children);
-	}
-	if (cont->marks) {
-		list_foreach(cont->marks, free);
-		list_free(cont->marks);
-	}
-	if (cont->parent) {
-		remove_child(cont);
-	}
-	if (cont->name) {
-		free(cont->name);
-	}
-	free(cont);
-}
-
 swayc_t *destroy_output(swayc_t *output) {
 	if (!sway_assert(output, "null output passed to destroy_output")) {
 		return NULL;