types FEATURE support boolean data types
diff --git a/src/plugins_types.c b/src/plugins_types.c
index 244b7ff..9b88174 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -349,6 +349,7 @@
         return LY_EINVAL;
     }
 }
+
 /**
  * @brief Validate and canonize value of the YANG built-in signed integer types.
  *
@@ -1014,6 +1015,75 @@
     return LY_SUCCESS;
 }
 
+/**
+ * @brief Validate value of the YANG built-in boolean type.
+ *
+ * Implementation of the ly_type_validate_clb.
+ */
+static LY_ERR
+ly_type_validate_boolean(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+                         const char **canonized, struct ly_err_item **err, void **priv)
+{
+    int8_t i;
+
+    if (value_len == 4 && !strncmp(value, "true", 4)) {
+        i = 1;
+    } else if (value_len == 5 && !strncmp(value, "false", 5)) {
+        i = 0;
+    } else {
+        char *errmsg;
+        asprintf(&errmsg, "Invalid boolean value \"%.*s\".", (int)value_len, value);
+        *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+        return LY_EVALID;
+    }
+
+    if (options & LY_TYPE_OPTS_CANONIZE) {
+        if (i) {
+            *canonized = lydict_insert(ctx, "true", 4);
+        } else {
+            *canonized = lydict_insert(ctx, "false", 5);
+        }
+    }
+
+    if (options & LY_TYPE_OPTS_STORE) {
+        /* save for the store callback */
+        *priv = malloc(sizeof i);
+        if (!(*priv)) {
+            *err = ly_err_new(LY_LLERR, LY_EMEM, 0, "Memory allocation failed.", NULL, NULL);
+            return LY_EMEM;
+        }
+        *(int8_t*)(*priv) = i;
+    }
+
+    if (options & LY_TYPE_OPTS_DYNAMIC) {
+        free((char*)value);
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Store value of the YANG built-in boolean type.
+ *
+ * Implementation of the ly_type_store_clb.
+ */
+static LY_ERR
+ly_type_store_boolean(struct ly_ctx *UNUSED(ctx), struct lysc_type *UNUSED(type), int options,
+                   struct lyd_value *value, struct ly_err_item **UNUSED(err), void **priv)
+{
+    if (options & LY_TYPE_OPTS_VALIDATE) {
+        /* the value was prepared by ly_type_validate_enum() */
+        value->boolean = *(int8_t*)(*priv);
+        free(*priv);
+    } else {
+        /* TODO if there is usecase for store without validate */
+        LOGINT(NULL);
+        return LY_EINT;
+    }
+
+    return LY_SUCCESS;
+}
+
 struct lysc_type_plugin ly_builtin_type_plugins[LY_DATA_TYPE_COUNT] = {
     {0}, /* LY_TYPE_UNKNOWN */
     {.type = LY_TYPE_BINARY, .validate = ly_type_validate_binary, .store = NULL, .free = NULL},
@@ -1023,7 +1093,7 @@
     {.type = LY_TYPE_UINT64, .validate = ly_type_validate_uint, .store = ly_type_store_uint, .free = NULL},
     {.type = LY_TYPE_STRING, .validate = ly_type_validate_string, .store = NULL, .free = NULL},
     {.type = LY_TYPE_BITS, .validate = ly_type_validate_bits, .store = ly_type_store_bits, .free = ly_type_free_bits},
-    {0}, /* TODO LY_TYPE_BOOL */
+    {.type = LY_TYPE_BOOL, .validate = ly_type_validate_boolean, .store = ly_type_store_boolean, .free = NULL},
     {.type = LY_TYPE_DEC64, .validate = ly_type_validate_decimal64, .store = ly_type_store_decimal64, .free = NULL},
     {0}, /* TODO LY_TYPE_EMPTY */
     {.type = LY_TYPE_ENUM, .validate = ly_type_validate_enum, .store = ly_type_store_enum, .free = NULL},
diff --git a/tests/features/test_types.c b/tests/features/test_types.c
index 329c150..536069d 100644
--- a/tests/features/test_types.c
+++ b/tests/features/test_types.c
@@ -72,7 +72,8 @@
             "leaf dec64 {type decimal64 {fraction-digits 1; range 1.5..10;}}"
             "leaf dec64-norestr {type decimal64 {fraction-digits 18;}}"
             "leaf str {type string {length 8..10; pattern '[a-z ]*';}}"
-            "leaf str-norestr {type string;}}";
+            "leaf str-norestr {type string;}"
+            "leaf bool {type boolean;}}";
 
     s = calloc(1, sizeof *s);
     assert_non_null(s);
@@ -507,6 +508,46 @@
     s->func = NULL;
 }
 
+static void
+test_boolean(void **state)
+{
+    struct state_s *s = (struct state_s*)(*state);
+    s->func = test_boolean;
+
+    struct lyd_node *tree;
+    struct lyd_node_term *leaf;
+
+    const char *data = "<bool xmlns=\"urn:tests:types\">true</bool>";
+
+    /* valid data */
+    assert_non_null(tree = lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+    assert_int_equal(LYS_LEAF, tree->schema->nodetype);
+    assert_string_equal("bool", tree->schema->name);
+    leaf = (struct lyd_node_term*)tree;
+    assert_string_equal("true", leaf->value.canonized);
+    assert_int_equal(1, leaf->value.boolean);
+    lyd_free_all(tree);
+
+    data = "<bool xmlns=\"urn:tests:types\">false</bool>";
+    assert_non_null(tree = lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+    assert_int_equal(LYS_LEAF, tree->schema->nodetype);
+    assert_string_equal("bool", tree->schema->name);
+    leaf = (struct lyd_node_term*)tree;
+    assert_string_equal("false", leaf->value.canonized);
+    assert_int_equal(0, leaf->value.boolean);
+    lyd_free_all(tree);
+
+    /* invalid value */
+    data = "<bool xmlns=\"urn:tests:types\">unsure</bool>";
+    assert_null(lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+    logbuf_assert("Invalid boolean value \"unsure\". /");
+
+    data = "<bool xmlns=\"urn:tests:types\"> true</bool>";
+    assert_null(lyd_parse_mem(s->ctx, data, LYD_XML, 0));
+    logbuf_assert("Invalid boolean value \" true\". /");
+
+    s->func = NULL;
+}
 
 int main(void)
 {
@@ -518,6 +559,7 @@
         cmocka_unit_test_setup_teardown(test_bits, setup, teardown),
         cmocka_unit_test_setup_teardown(test_enums, setup, teardown),
         cmocka_unit_test_setup_teardown(test_binary, setup, teardown),
+        cmocka_unit_test_setup_teardown(test_boolean, setup, teardown),
     };
 
     return cmocka_run_group_tests(tests, NULL, NULL);