diff --git a/modules/core/src/persistence.cpp b/modules/core/src/persistence.cpp
index 9c7b0f236b..1b1e956f20 100644
--- a/modules/core/src/persistence.cpp
+++ b/modules/core/src/persistence.cpp
@@ -5217,7 +5217,7 @@ FileStorage& operator << (FileStorage& fs, const String& str)
     }
     else if( fs.state == NAME_EXPECTED + INSIDE_MAP )
     {
-        if( !cv_isalpha(*_str) )
+        if (!cv_isalpha(*_str) && *_str != '_')
             CV_Error_( CV_StsError, ("Incorrect element name %s", _str) );
         fs.elname = str;
         fs.state = VALUE_EXPECTED + INSIDE_MAP;
diff --git a/modules/core/test/test_io.cpp b/modules/core/test/test_io.cpp
index 0c401f8ebd..b53c43c83b 100644
--- a/modules/core/test/test_io.cpp
+++ b/modules/core/test/test_io.cpp
@@ -566,3 +566,14 @@ TEST(Core_InputOutput, FileStorage)
     sprintf(arr, "sprintf is hell %d", 666);
     EXPECT_NO_THROW(f << arr);
 }
+
+TEST(Core_InputOutput, FileStorageKey)
+{
+    cv::FileStorage f("dummy.yml", cv::FileStorage::WRITE | cv::FileStorage::MEMORY);
+
+    EXPECT_NO_THROW(f << "key1" << "value1");
+    EXPECT_NO_THROW(f << "_key2" << "value2");
+    EXPECT_NO_THROW(f << "key_3" << "value3");
+    const std::string expected = "%YAML:1.0\nkey1: value1\n_key2: value2\nkey_3: value3\n";
+    ASSERT_STREQ(f.releaseAndGetString().c_str(), expected.c_str());
+}