diff --git a/src/traft/event.rs b/src/traft/event.rs
index 4a1a076b00357a206be7b9a96878293bdb773e9e..0d2c7dede1d614aad432c17dadbdb8642f6fe982 100644
--- a/src/traft/event.rs
+++ b/src/traft/event.rs
@@ -9,20 +9,14 @@ use ::tarantool::fiber::{mutex::MutexGuard, Cond, Mutex};
 use ::tarantool::proc;
 use ::tarantool::unwrap_or;
 
-use crate::define_str_enum;
 use crate::tlog;
 use crate::traft::error::Error;
 use crate::traft::Result;
 use crate::unwrap_ok_or;
-use thiserror::Error;
 
 pub type BoxResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;
 
-#[derive(Error, Debug)]
-#[error("unknown event {0}")]
-pub struct EventFromStrError(pub String);
-
-define_str_enum! {
+::tarantool::define_str_enum! {
     ////////////////////////////////////////////////////////////////////////////
     /// An enumeration of builtin events
     pub enum Event {
@@ -35,8 +29,6 @@ define_str_enum! {
         RaftLoopNeeded = "raft.loop-needed",
         RaftEntryApplied = "raft.entry-applied",
     }
-
-    FromStr::Err = EventFromStrError;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/traft/mod.rs b/src/traft/mod.rs
index 56b545976633a62276b25dbabe26615fe536e4c9..ac5346f1f695b202013f014624af7ab7455374c6 100644
--- a/src/traft/mod.rs
+++ b/src/traft/mod.rs
@@ -844,55 +844,37 @@ impl Encode for JoinResponse {}
 
 ///////////////////////////////////////////////////////////////////////////////
 
-crate::define_str_enum! {
+::tarantool::define_str_enum! {
     /// Activity state of an instance.
+    #[derive(Default)]
     pub enum CurrentGradeVariant {
-        // Instance has gracefully shut down or has not been started yet.
+        /// Instance has gracefully shut down or has not been started yet.
+        #[default]
         Offline = "Offline",
-        // Instance has synced by commit index.
+        /// Instance has synced by commit index.
         RaftSynced = "RaftSynced",
-        // Instance has configured replication.
+        /// Instance has configured replication.
         Replicated = "Replicated",
-        // Instance has configured sharding.
+        /// Instance has configured sharding.
         ShardingInitialized = "ShardingInitialized",
-        // Instance is active and is handling requests.
+        /// Instance is active and is handling requests.
         Online = "Online",
-        // Instance has permanently removed from cluster.
+        /// Instance has permanently removed from cluster.
         Expelled = "Expelled",
     }
-    FromStr::Err = UnknownGrade;
 }
 
-#[derive(thiserror::Error, Debug)]
-#[error("unknown grade {0:?}")]
-pub struct UnknownGrade(pub String);
-
-impl Default for CurrentGradeVariant {
-    fn default() -> Self {
-        Self::Offline
-    }
-}
-
-crate::define_str_enum! {
+::tarantool::define_str_enum! {
+    #[derive(Default)]
     pub enum TargetGradeVariant {
-        // Instance should be configured up
+        /// Instance should be configured up
         Online = "Online",
-        // Instance should be gracefully shut down
+        /// Instance should be gracefully shut down
+        #[default]
         Offline = "Offline",
-        // Instance should be removed from cluster
+        /// Instance should be removed from cluster
         Expelled = "Expelled",
     }
-    FromStr::Err = UnknownTargetGrade;
-}
-
-#[derive(thiserror::Error, Debug)]
-#[error("unknown target grade {0:?}")]
-pub struct UnknownTargetGrade(pub String);
-
-impl Default for TargetGradeVariant {
-    fn default() -> Self {
-        Self::Offline
-    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/traft/node.rs b/src/traft/node.rs
index 5eb48042ab84eda95acdca287f6f5c31b02d82d2..3670f2b7b81809c5829ae13ae3742974808ad3a8 100644
--- a/src/traft/node.rs
+++ b/src/traft/node.rs
@@ -65,18 +65,14 @@ use super::{CurrentGrade, CurrentGradeVariant, TargetGradeVariant};
 
 type RawNode = raft::RawNode<RaftSpaceAccess>;
 
-crate::define_str_enum! {
+::tarantool::define_str_enum! {
     pub enum RaftState {
         Follower = "Follower",
         Candidate = "Candidate",
         Leader = "Leader",
         PreCandidate = "PreCandidate",
     }
-    FromStr::Err = UnknownRaftState;
 }
-#[derive(thiserror::Error, Debug)]
-#[error("unknown raft state {0}")]
-pub struct UnknownRaftState(pub String);
 
 impl RaftState {
     pub fn is_leader(&self) -> bool {
diff --git a/src/traft/storage.rs b/src/traft/storage.rs
index 2ca031b6638d22b0f3c91f14b0503b49b2d53fcd..eadda6be32a7107c1c3cafcd8f2a3ce0b00ef228 100644
--- a/src/traft/storage.rs
+++ b/src/traft/storage.rs
@@ -1,9 +1,7 @@
 use ::tarantool::index::{Index, IndexIterator, IteratorType};
 use ::tarantool::space::{FieldType, Space};
 use ::tarantool::tuple::{DecodeOwned, ToTupleBuffer, Tuple};
-use thiserror::Error;
 
-use crate::define_str_enum;
 use crate::traft;
 use crate::traft::error::Error;
 use crate::traft::rpc::sharding::cfg::ReplicasetWeights;
@@ -20,7 +18,7 @@ use super::{Migration, RaftSpaceAccess};
 // ClusterSpace
 ////////////////////////////////////////////////////////////////////////////////
 
-define_str_enum! {
+::tarantool::define_str_enum! {
     /// An enumeration of builtin cluster-wide spaces
     pub enum ClusterSpace {
         Group = "raft_group",
@@ -28,14 +26,8 @@ define_str_enum! {
         Replicasets = "replicasets",
         Migrations = "migrations",
     }
-
-    FromStr::Err = UnknownClusterSpace;
 }
 
-#[derive(Error, Debug)]
-#[error("unknown cluster space {0}")]
-pub struct UnknownClusterSpace(pub String);
-
 impl ClusterSpace {
     #[inline]
     fn get(&self) -> tarantool::Result<Space> {
@@ -77,21 +69,15 @@ impl ClusterSpace {
 // StateKey
 ////////////////////////////////////////////////////////////////////////////////
 
-define_str_enum! {
+::tarantool::define_str_enum! {
     /// An enumeration of builtin raft spaces
     pub enum StateKey {
         ReplicationFactor = "replication_factor",
         VshardBootstrapped = "vshard_bootstrapped",
         DesiredSchemaVersion = "desired_schema_version",
     }
-
-    FromStr::Err = UnknownStateKey;
 }
 
-#[derive(Error, Debug)]
-#[error("unknown state key {0}")]
-pub struct UnknownStateKey(pub String);
-
 ////////////////////////////////////////////////////////////////////////////////
 // Storage
 ////////////////////////////////////////////////////////////////////////////////
@@ -439,13 +425,11 @@ impl Peers {
 
 macro_rules! define_peer_fields {
     ($($field:ident: $ty:ty = ($name:literal, $tt_ty:path))+) => {
-        crate::define_str_enum! {
+        ::tarantool::define_str_enum! {
             /// An enumeration of raft_space field names
             pub enum PeerField {
                 $($field = $name,)+
             }
-
-            FromStr::Err = UnknownPeerField;
         }
 
         pub mod peer_field {
@@ -518,10 +502,6 @@ define_peer_fields! {
     FailureDomain  : traft::FailureDomain = ("failure_domain",  FieldType::Map)
 }
 
-#[derive(Error, Debug)]
-#[error(r#"unknown peer field "{0}""#)]
-pub struct UnknownPeerField(pub String);
-
 impl tarantool::tuple::TupleIndex for PeerField {
     fn get_field<'a, T>(self, tuple: &'a Tuple) -> tarantool::Result<Option<T>>
     where
diff --git a/src/util.rs b/src/util.rs
index 04bd79698885dc2423e584ca3c545c72ec1de1f6..aadd362831ed5a05820db129986181b3cbb161a6 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -154,104 +154,6 @@ macro_rules! stringify_debug {
     }};
 }
 
-#[macro_export]
-macro_rules! define_str_enum {
-    (
-        $(#[$meta:meta])*
-        pub enum $enum:ident { $($space:tt = $str:literal,)+ }
-        FromStr::Err = $err:ident;
-    ) => {
-        $(#[$meta])*
-        #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
-        pub enum $enum {
-            $( #[doc = $str] $space, )+
-        }
-
-        impl $enum {
-            pub const fn as_str(&self) -> &'static str {
-                match self {
-                    $( Self::$space => $str, )+
-                }
-            }
-        }
-
-        impl AsRef<str> for $enum {
-            fn as_ref(&self) -> &str {
-                self.as_str()
-            }
-        }
-
-        impl From<$enum> for String {
-            fn from(e: $enum) -> Self {
-                e.as_str().into()
-            }
-        }
-
-        impl std::str::FromStr for $enum {
-            type Err = $err;
-
-            fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
-                match s {
-                    $( $str => Ok(Self::$space), )+
-                    _ => Err($err(s.into())),
-                }
-            }
-        }
-
-        impl std::fmt::Display for $enum {
-            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
-                f.write_str(self.as_str())
-            }
-        }
-
-        impl serde::Serialize for $enum {
-            #[inline]
-            fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
-            where
-                S: serde::Serializer,
-            {
-                serializer.serialize_str(self.as_str())
-            }
-        }
-
-        impl<'de> serde::Deserialize<'de> for $enum {
-            fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
-            where
-                D: serde::Deserializer<'de>,
-            {
-                use serde::de::Error;
-                let tmp = <&str>::deserialize(deserializer)?;
-                let res = tmp.parse().map_err(|_| Error::unknown_variant(tmp, &[$($str),+]))?;
-                Ok(res)
-            }
-        }
-
-        impl<L: ::tarantool::tlua::AsLua> ::tarantool::tlua::Push<L> for $enum {
-            type Err = ::tarantool::tlua::Void;
-            fn push_to_lua(&self, lua: L) -> ::tarantool::tlua::PushResult<L, Self> {
-                ::tarantool::tlua::PushInto::push_into_lua(self.as_str(), lua)
-            }
-        }
-        impl<L: ::tarantool::tlua::AsLua> ::tarantool::tlua::PushOne<L> for $enum {}
-
-        impl<L: ::tarantool::tlua::AsLua> ::tarantool::tlua::PushInto<L> for $enum {
-            type Err = ::tarantool::tlua::Void;
-            fn push_into_lua(self, lua: L) -> ::tarantool::tlua::PushIntoResult<L, Self> {
-                ::tarantool::tlua::PushInto::push_into_lua(self.as_str(), lua)
-            }
-        }
-        impl<L: ::tarantool::tlua::AsLua> ::tarantool::tlua::PushOneInto<L> for $enum {}
-
-        impl<L: ::tarantool::tlua::AsLua> ::tarantool::tlua::LuaRead<L> for $enum {
-            fn lua_read_at_position(lua: L, index: std::num::NonZeroI32) -> ::std::result::Result<Self, L> {
-                ::tarantool::tlua::StringInLua::lua_read_at_position(&lua, index).ok()
-                    .and_then(|s| s.parse().ok())
-                    .ok_or(lua)
-            }
-        }
-    }
-}
-
 #[macro_export]
 macro_rules! define_string_newtype {
     (