diff --git a/doc/configuration.rst b/doc/configuration.rst
index 448523570402bafa8bd18b822cd03b57007189ff..97978b707e96db1873b63456234c09f8217eb2ee 100644
--- a/doc/configuration.rst
+++ b/doc/configuration.rst
@@ -438,3 +438,15 @@ of the limitations will be hopefully removed in the near future.
   - Legacy key import requires a private key.
   - Legacy key export is not implemented.
   - DS record export is not implemented.
+
+.. _dnssec-keyusage:
+
+DNSSEC keys used by multiple zones 
+----------------------------------
+
+Using same key for multiple zones with automatic key management is possible. 
+However, all zones must be listed in keyusage (keys directory) or they will be deleted,
+when they retire in any zone.
+
+If keys are added manually as published, but not active (for next rollover event), they are added automatically.
+
diff --git a/src/dnssec/Makefile.am b/src/dnssec/Makefile.am
index 764cb424db198acf4987e2a06c5c2f3fd25a0179..13ac2c45e93ff3980e69fc112b65bd1bee1b398c 100644
--- a/src/dnssec/Makefile.am
+++ b/src/dnssec/Makefile.am
@@ -65,6 +65,7 @@ include_dnssec_HEADERS = \
 	lib/dnssec/keyid.h \
 	lib/dnssec/keystate.h \
 	lib/dnssec/keystore.h \
+	lib/dnssec/keyusage.h \
 	lib/dnssec/keytag.h \
 	lib/dnssec/list.h \
 	lib/dnssec/nsec.h \
@@ -124,6 +125,7 @@ libdnssec_la_SOURCES = \
 	lib/keystore/pkcs11.c \
 	lib/keystore/pkcs8.c \
 	lib/keystore/pkcs8_dir.c \
+	lib/keyusage/keyusage.c	 \
 	lib/list/list.c \
 	lib/list/ucw_clists.h \
 	lib/nsec/bitmap.c \
diff --git a/src/dnssec/lib/dnssec/keyusage.h b/src/dnssec/lib/dnssec/keyusage.h
new file mode 100644
index 0000000000000000000000000000000000000000..916d5a2d072d989e1e67fa1efd6b64300c914c21
--- /dev/null
+++ b/src/dnssec/lib/dnssec/keyusage.h
@@ -0,0 +1,40 @@
+/*  Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <dnssec/list.h>
+
+typedef struct record {
+	char *keytag;
+	dnssec_list_t *zones;
+} record_keyusage_t;
+
+typedef dnssec_list_t dnssec_keyusage_t;
+
+int dnssec_keyusage_add(dnssec_keyusage_t *keyusage, const char *keytag, char *zone);
+
+int dnssec_keyusage_remove(dnssec_keyusage_t *keyusage, const char *keytag, char *zone);
+
+bool dnssec_keyusage_is_used(dnssec_keyusage_t *keyusage, const char *keytag);
+
+int dnssec_keyusage_load(dnssec_keyusage_t *keyusage, const char *filename);
+
+int dnssec_keyusage_save(dnssec_keyusage_t *keyusage, const char *filename);
+
+dnssec_keyusage_t *dnssec_keyusage_new(void);
+
+void dnssec_keyusage_free(dnssec_keyusage_t *keyusage);
diff --git a/src/dnssec/lib/event/action/initial_key.c b/src/dnssec/lib/event/action/initial_key.c
index bbe7fcb4d17e43aee59f6e4134a0723a6baff8c4..3e43e413fb172901aed06f7e3eae1891a1ee208f 100644
--- a/src/dnssec/lib/event/action/initial_key.c
+++ b/src/dnssec/lib/event/action/initial_key.c
@@ -22,6 +22,7 @@
 #include "shared.h"
 #include "event/action.h"
 #include "event/utils.h"
+#include "dnssec/keyusage.h"
 
 /*!
  * Scan zone keys and check if ZSK and KSK key exists.
@@ -58,6 +59,19 @@ static int generate_initial_key(dnssec_event_ctx_t *ctx, bool ksk)
 		return r;
 	}
 
+	if (!ksk) {
+		char *path;
+		if (asprintf(&path, "%s/keyusage", ctx->kasp->functions->base_path(ctx->kasp->ctx)) == -1){
+			return DNSSEC_ENOMEM;
+		}
+		dnssec_keyusage_t *keyusage = dnssec_keyusage_new();
+		dnssec_keyusage_load(keyusage, path);
+		dnssec_keyusage_add(keyusage, key->id, ctx->zone->name);
+		dnssec_keyusage_save(keyusage, path);
+		dnssec_keyusage_free(keyusage);
+		free(path);
+	}
+
 	key->timing.active  = ctx->now;
 	key->timing.publish = ctx->now;
 
diff --git a/src/dnssec/lib/event/action/zsk_rollover.c b/src/dnssec/lib/event/action/zsk_rollover.c
index 9fd1447700c5db60bae9e8cbb2cc8ba058c08b12..24f64c99b4423ec37e8bfa56f17bfca946099f07 100644
--- a/src/dnssec/lib/event/action/zsk_rollover.c
+++ b/src/dnssec/lib/event/action/zsk_rollover.c
@@ -18,6 +18,7 @@
 
 #include "dnssec/error.h"
 #include "dnssec/event.h"
+#include "dnssec/keyusage.h"
 #include "event/action.h"
 #include "dnssec/keystate.h"
 #include "event/utils.h"
@@ -169,6 +170,17 @@ static int exec_new_signatures(dnssec_event_ctx_t *ctx)
 	active->timing.retire = ctx->now;
 	rolling->timing.active = ctx->now;
 
+	char *path;
+	if (asprintf(&path, "%s/keyusage", ctx->kasp->functions->base_path(ctx->kasp->ctx)) == -1){
+		return DNSSEC_ENOMEM;
+	}
+	dnssec_keyusage_t *keyusage = dnssec_keyusage_new();
+	dnssec_keyusage_load(keyusage, path);
+	dnssec_keyusage_add(keyusage, rolling->id, ctx->zone->name);
+	dnssec_keyusage_save(keyusage, path);
+	dnssec_keyusage_free(keyusage);
+	free(path);
+
 	return dnssec_kasp_zone_save(ctx->kasp, ctx->zone);
 }
 
@@ -179,7 +191,33 @@ static int exec_remove_old_key(dnssec_event_ctx_t *ctx)
 		return DNSSEC_EINVAL;
 	}
 
+	char *path;
+	if (asprintf(&path, "%s/keyusage", ctx->kasp->functions->base_path(ctx->kasp->ctx)) == -1){
+		return DNSSEC_ENOMEM;
+	}
+
+	dnssec_keyusage_t *keyusage = dnssec_keyusage_new();
+	dnssec_keyusage_load(keyusage, path);
+	dnssec_keyusage_remove(keyusage, retired->id, ctx->zone->name);
+	dnssec_keyusage_save(keyusage, path);
+
 	retired->timing.remove = ctx->now;
+	dnssec_list_foreach(item, ctx->zone->keys) {
+		dnssec_kasp_key_t *key = dnssec_item_get(item);
+		if (key->id == retired->id) {
+			dnssec_list_remove(item);
+		}
+	}
+
+	if (dnssec_keyusage_is_used(keyusage, retired->id)) {
+		dnssec_keyusage_free(keyusage);
+		free(path);
+		return dnssec_kasp_zone_save(ctx->kasp, ctx->zone);
+	}
+	dnssec_keyusage_free(keyusage);
+	free(path);
+
+	dnssec_keystore_remove_key(ctx->keystore, retired->id);
 
 	return dnssec_kasp_zone_save(ctx->kasp, ctx->zone);
 }
diff --git a/src/dnssec/lib/keyusage/keyusage.c b/src/dnssec/lib/keyusage/keyusage.c
new file mode 100644
index 0000000000000000000000000000000000000000..dc4cfe748489fc49501ec0c91d28f03ddf1d8789
--- /dev/null
+++ b/src/dnssec/lib/keyusage/keyusage.c
@@ -0,0 +1,317 @@
+/*  Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dnssec/keyusage.h"
+#include "error.h"
+#include "string.h"
+#include "dnssec.h"
+#include <assert.h>
+#include "error.h"
+#include "kasp/dir/json.h"
+#include "kasp/internal.h"
+#include "shared.h"
+#include <string.h>
+
+int dnssec_keyusage_add(dnssec_keyusage_t *keyusage, const char *keytag, char *zone) {
+
+	char *lzone = strdup(zone);
+	dnssec_list_foreach(item, keyusage) {
+
+		record_keyusage_t *record = dnssec_item_get(item);
+		if (strcmp(record->keytag, keytag) == 0) {
+
+			if(!dnssec_list_contains(record->zones, lzone)) {
+				dnssec_list_append(record->zones, lzone);
+			}
+
+			return DNSSEC_EOK;
+		}
+	}
+
+	record_keyusage_t *record = malloc(sizeof(*record));
+	record->keytag = strdup(keytag);
+	record->zones = dnssec_list_new();
+
+	dnssec_list_append(record->zones, lzone);
+	dnssec_list_append(keyusage, record);
+
+	return DNSSEC_EOK;
+}
+
+int dnssec_keyusage_remove(dnssec_keyusage_t *keyusage, const char *keytag, char *zone) {
+
+	dnssec_list_foreach(item, keyusage) {
+		record_keyusage_t *record = dnssec_item_get(item);
+
+		if (strcmp(record->keytag, keytag) == 0) {
+			dnssec_list_foreach(item2, record->zones) {
+
+				char *tmp = dnssec_item_get(item2);
+
+				if(strcmp(tmp,zone)==0) {
+
+					free(tmp);
+					dnssec_list_remove(item2);
+
+					if (dnssec_list_is_empty(record->zones)) {
+						free(record->keytag);
+						dnssec_list_free(record->zones);
+						free(record);
+						dnssec_list_remove(item);
+					}
+
+					return DNSSEC_EOK;
+				}
+			}
+
+		}
+	}
+	return DNSSEC_ENOENT;
+}
+
+bool dnssec_keyusage_is_used(dnssec_keyusage_t *keyusage, const char *keytag) {
+
+	if (dnssec_list_is_empty(keyusage)) {
+		return false;
+	}
+
+	dnssec_list_foreach(item, keyusage) {
+		record_keyusage_t *record = dnssec_item_get(item);
+
+		if(record == NULL || record->keytag == NULL) {
+			return false;
+		}
+
+		if (strcmp(record->keytag, keytag) == 0) {
+			return !dnssec_list_is_empty(record->zones);
+		}
+	}
+	return false;
+}
+
+static int import_keyusage(dnssec_keyusage_t *keyusage, const json_t *json)
+{
+	json_t *jrecord = NULL;
+	int a, b;
+	if (!json_is_array(json)) {
+		if (json_is_null(json)) {
+			return DNSSEC_EOK;
+		} else {
+			return DNSSEC_CONFIG_MALFORMED;
+		}
+	}
+	json_array_foreach(json, a, jrecord) {
+		json_t *jkeytag = NULL;
+		jkeytag = json_object_get(jrecord, "keytag");
+
+		record_keyusage_t *record = malloc(sizeof(*record));
+		if (record == NULL) {
+			return DNSSEC_ENOMEM;
+		}
+
+		int r = decode_string(jkeytag, &record->keytag);
+		if (r != DNSSEC_EOK) {
+			return r;
+		}
+
+		json_t *jzones = NULL, *jzone = NULL;
+		jzones = json_object_get(jrecord, "zones");
+		record->zones = dnssec_list_new();
+
+		json_array_foreach(jzones, b, jzone) {
+			char *zone;
+			int r = decode_string(jzone, &zone);
+			if (r != DNSSEC_EOK) {
+				return r;
+			}
+			dnssec_list_append(record->zones, zone);
+		}
+		dnssec_list_append(keyusage, record);
+	}
+
+	return DNSSEC_EOK;
+}
+
+static int export_keyusage(dnssec_keyusage_t *keyusage, json_t **json)
+{
+	assert(keyusage);
+	assert(json);
+	record_keyusage_t *record;
+	int r;
+
+	if (dnssec_list_is_empty(keyusage)) {
+		return DNSSEC_EOK;
+	}
+
+	json_t *jrecords = json_array();
+	if (!jrecords) {
+		return DNSSEC_ENOMEM;
+	}
+
+	json_t *jkeytag = NULL;
+	json_t *jzone = NULL;
+	json_t *jzones = NULL;
+
+	dnssec_list_foreach(item, keyusage) {
+		record = dnssec_item_get(item);
+
+		json_t *jzones = json_array();
+		if (!jzones) {
+			json_array_clear(jrecords);
+			return DNSSEC_ENOMEM;
+		}
+
+		r = encode_string(&record->keytag, &jkeytag);
+		if (r != DNSSEC_EOK) {
+			json_decref(jkeytag);
+			goto error;
+		}
+		dnssec_list_foreach(item, record->zones) {
+
+			const char *zone = dnssec_item_get(item);
+			r = encode_string(&zone, &jzone);
+
+			if (r != DNSSEC_EOK) {
+				json_decref(jzone);
+				goto error;
+			}
+
+			if (json_array_append_new(jzones, jzone)) {
+				r = DNSSEC_ENOMEM;
+				goto error;
+			}
+		}
+		json_t *jrecord = json_object();
+		if (!jrecord) {
+			r = DNSSEC_ENOMEM;
+			goto error;
+		}
+
+		if (json_object_set(jrecord, "keytag",jkeytag)) {
+			json_object_clear(jrecord);
+			r = DNSSEC_ENOMEM;
+			goto error;
+		}
+		json_decref(jkeytag);
+
+		if (json_object_set(jrecord, "zones",jzones)) {
+			json_object_clear(jrecord);
+			r = DNSSEC_ENOMEM;
+			goto error;
+		}
+		json_decref(jzones);
+
+		if (json_array_append_new(jrecords, jrecord)) {
+			json_object_clear(jrecord);
+			r = DNSSEC_ENOMEM;
+			goto error;
+		}
+	}
+	*json = jrecords;
+
+	return DNSSEC_EOK;
+error:
+	json_array_clear(jzones);
+	json_array_clear(jrecords);
+	return r;
+
+}
+
+int dnssec_keyusage_load(dnssec_keyusage_t *keyusage, const char *filename)
+{
+	assert(keyusage);
+	assert(filename);
+
+	dnssec_list_clear(keyusage);
+
+	_cleanup_fclose_ FILE *file = fopen(filename, "r");
+	if (!file) {
+		return DNSSEC_NOT_FOUND;
+	}
+
+	json_error_t error = { 0 };
+	_json_cleanup_ json_t *json = json_loadf(file, JSON_LOAD_OPTIONS, &error);
+	if (!json) {
+		if (error.position != 1) {
+			return DNSSEC_CONFIG_MALFORMED;
+		} else {
+			return DNSSEC_EOK;
+		}
+	}
+
+	return import_keyusage(keyusage, json);
+}
+
+int dnssec_keyusage_save(dnssec_keyusage_t *keyusage, const char *filename)
+{
+	assert(keyusage);
+	assert(filename);
+
+	_json_cleanup_ json_t *json = NULL;
+	int r = export_keyusage(keyusage, &json);
+	if (r != DNSSEC_EOK) {
+		return r;
+	}
+
+	_cleanup_fclose_ FILE *file = fopen(filename, "w");
+	if (!file) {
+		return DNSSEC_NOT_FOUND;
+	}
+
+	if (json)
+	{
+		r = json_dumpf(json, file, JSON_DUMP_OPTIONS);
+		if (r != DNSSEC_EOK) {
+			return r;
+		}
+	}
+
+	fputc('\n', file);
+	return DNSSEC_EOK;
+}
+
+/* -- public API ----------------------------------------------------------- */
+
+_public_
+dnssec_keyusage_t *dnssec_keyusage_new()
+{
+	dnssec_keyusage_t *keyusage = dnssec_list_new();
+	return keyusage;
+}
+
+_public_
+void dnssec_keyusage_free(dnssec_keyusage_t *keyusage)
+{
+	if (keyusage == NULL) {
+		return;
+	}
+
+	if (!dnssec_list_is_empty(keyusage)) {
+		dnssec_list_foreach(item, keyusage) {
+			record_keyusage_t *record = dnssec_item_get(item);
+
+			free(record->keytag);
+			dnssec_list_foreach(item2, record->zones) {
+				char *zone = dnssec_item_get(item2);
+				free(zone);
+			}
+			dnssec_list_free(record->zones);
+			free(record);
+		}
+	}
+	dnssec_list_free(keyusage);
+	keyusage = NULL;
+}
diff --git a/src/dnssec/tests/.gitignore b/src/dnssec/tests/.gitignore
index bdbb8facbb25f061778b53b874d9b526967700ae..5075e739c2e7c3b1b4b0a6d28519d537cdcf2f71 100644
--- a/src/dnssec/tests/.gitignore
+++ b/src/dnssec/tests/.gitignore
@@ -9,6 +9,7 @@
 /event_nsec3_resalt
 /kasp_dir_escape
 /kasp_dir_file
+/keyusage
 /kasp_policy
 /kasp_store
 /key
diff --git a/src/dnssec/tests/Makefile.am b/src/dnssec/tests/Makefile.am
index 2821b55c3f8ca692bf6a67bfe28434ff7f8cfca2..6f3fed12f8715ce48607089dc869b7eec0d84cfc 100644
--- a/src/dnssec/tests/Makefile.am
+++ b/src/dnssec/tests/Makefile.am
@@ -34,6 +34,7 @@ check_PROGRAMS = \
 	keystore_pkcs8	\
 	keystore_pkcs8_dir \
 	keytag		\
+	keyusage	\
 	list		\
 	nsec_bitmap	\
 	nsec_hash	\
diff --git a/src/dnssec/tests/keyusage.c b/src/dnssec/tests/keyusage.c
new file mode 100644
index 0000000000000000000000000000000000000000..31f21140743ac6c2e3b879e90b8f2e77e55e0aae
--- /dev/null
+++ b/src/dnssec/tests/keyusage.c
@@ -0,0 +1,108 @@
+/*  Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <tap/basic.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "dnssec/keyusage.h"
+#include "dnssec/error.h"
+#include "dnssec.h"
+
+static void test_keyusage_empty(void)
+{
+	diag("%s", __func__);
+
+	dnssec_keyusage_t *k = dnssec_keyusage_new();
+
+	remove("/tmp/keyusage.json");
+
+	ok(dnssec_keyusage_load(k, "/tmp/keyusage.json")== DNSSEC_NOT_FOUND, "kayusage_load empty, no keyusage");
+
+	ok(dnssec_list_is_empty(k), "List of records is empty.");
+
+	ok(dnssec_keyusage_save(k, "/tmp/keyusage.json") == DNSSEC_EOK , "kayusage_save empty");
+
+	ok(dnssec_keyusage_load(k, "/tmp/keyusage.json")== DNSSEC_EOK , "kayusage_load empty");
+
+	ok(dnssec_list_is_empty(k), "List of records is empty.");
+
+	dnssec_keyusage_free(k);
+}
+
+static void test_keyusage_basic(void)
+{
+	diag("%s", __func__);
+
+	dnssec_keyusage_t *k = NULL;
+
+	k = dnssec_keyusage_new();
+	ok(dnssec_list_is_empty(k), "List of records is empty.");
+
+	dnssec_keyusage_add(k, "prvni", "zona");
+
+	ok(!dnssec_list_is_empty(k), "List of records is not empty.");
+	// Check added key being used
+	ok(dnssec_keyusage_is_used(k, "prvni"), "Key is used.");
+	// Remove added key and check empty record
+	dnssec_keyusage_remove(k, "prvni", "zona");
+	ok(dnssec_list_is_empty(k), "List of records is empty.");
+	ok(!dnssec_keyusage_is_used(k, "prvni"), "Key is not used.");
+	// Check if key is used when one of zones is deleted
+	dnssec_keyusage_add(k, "prvni", "zona");
+	dnssec_keyusage_add(k, "prvni", "zona2");
+	dnssec_keyusage_remove(k, "prvni", "zona");
+	ok(dnssec_keyusage_is_used(k, "prvni"), "Key is used.");
+
+	// Check if key is unused after deleting both zones
+	dnssec_keyusage_remove(k, "prvni", "zona2");
+	ok(!dnssec_keyusage_is_used(k, "prvni"), "Key is not used.");
+
+	dnssec_keyusage_free(k);
+}
+
+static void test_keyusage_file(void)
+{
+	dnssec_keyusage_t *k = NULL;
+	k = dnssec_keyusage_new();
+	dnssec_keyusage_add(k, "prvni", "zona");
+	dnssec_keyusage_add(k, "prvni", "zona2");
+	dnssec_keyusage_add(k, "druhy", "zona");
+
+	ok(dnssec_keyusage_save(k, "/tmp/keyusage.json") == DNSSEC_EOK , "kayusage_save");
+
+	dnssec_keyusage_free(k);
+	k = dnssec_keyusage_new();
+
+	ok(!dnssec_keyusage_is_used(k, "prvni"), "Key is not used - freed succesfully.");
+	ok(!dnssec_keyusage_is_used(k, "druhy"), "Key is not used - freed succesfully.");
+
+	ok(dnssec_keyusage_load(k, "/tmp/keyusage.json")== DNSSEC_EOK , "kayusage_load");
+
+	ok(dnssec_keyusage_is_used(k, "prvni"), "Key is used - loaded succesfully.");
+	ok(dnssec_keyusage_is_used(k, "druhy"), "Key is used - loaded succesfully.");
+
+	dnssec_keyusage_free(k);
+}
+
+int main(int argc, char *argv[])
+{
+	plan_lazy();
+	test_keyusage_empty();
+	test_keyusage_basic();
+	test_keyusage_file();
+	return 0;
+}