diff --git a/src/file/format/json.rs b/src/file/format/json.rs
index 1720cb60..bd506f0d 100644
--- a/src/file/format/json.rs
+++ b/src/file/format/json.rs
@@ -1,5 +1,6 @@
 use std::error::Error;
 
+use crate::format;
 use crate::map::Map;
 use crate::value::{Value, ValueKind};
 
@@ -8,13 +9,8 @@ pub fn parse(
     text: &str,
 ) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
     // Parse a JSON object value from the text
-    // TODO: Have a proper error fire if the root of a file is ever not a Table
     let value = from_json_value(uri, &serde_json::from_str(text)?);
-    match value.kind {
-        ValueKind::Table(map) => Ok(map),
-
-        _ => Ok(Map::new()),
-    }
+    format::extract_root_table(uri, value)
 }
 
 fn from_json_value(uri: Option<&String>, value: &serde_json::Value) -> Value {
diff --git a/src/file/format/json5.rs b/src/file/format/json5.rs
index 92aaa8f9..99003bd0 100644
--- a/src/file/format/json5.rs
+++ b/src/file/format/json5.rs
@@ -1,6 +1,6 @@
 use std::error::Error;
 
-use crate::error::{ConfigError, Unexpected};
+use crate::format;
 use crate::map::Map;
 use crate::value::{Value, ValueKind};
 
@@ -20,20 +20,8 @@ pub fn parse(
     uri: Option<&String>,
     text: &str,
 ) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
-    match json5_rs::from_str::<Val>(text)? {
-        Val::String(ref value) => Err(Unexpected::Str(value.clone())),
-        Val::Integer(value) => Err(Unexpected::I64(value)),
-        Val::Float(value) => Err(Unexpected::Float(value)),
-        Val::Boolean(value) => Err(Unexpected::Bool(value)),
-        Val::Array(_) => Err(Unexpected::Seq),
-        Val::Null => Err(Unexpected::Unit),
-        Val::Object(o) => match from_json5_value(uri, Val::Object(o)).kind {
-            ValueKind::Table(map) => Ok(map),
-            _ => Ok(Map::new()),
-        },
-    }
-    .map_err(|err| ConfigError::invalid_root(uri, err))
-    .map_err(|err| Box::new(err) as Box<dyn Error + Send + Sync>)
+    let value = from_json5_value(uri, json5_rs::from_str::<Val>(text)?);
+    format::extract_root_table(uri, value)
 }
 
 fn from_json5_value(uri: Option<&String>, value: Val) -> Value {
diff --git a/src/file/format/ron.rs b/src/file/format/ron.rs
index fb2b0636..9ac81a9d 100644
--- a/src/file/format/ron.rs
+++ b/src/file/format/ron.rs
@@ -1,5 +1,6 @@
 use std::error::Error;
 
+use crate::format;
 use crate::map::Map;
 use crate::value::{Value, ValueKind};
 
@@ -8,11 +9,7 @@ pub fn parse(
     text: &str,
 ) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
     let value = from_ron_value(uri, ron::from_str(text)?)?;
-    match value.kind {
-        ValueKind::Table(map) => Ok(map),
-
-        _ => Ok(Map::new()),
-    }
+    format::extract_root_table(uri, value)
 }
 
 fn from_ron_value(
diff --git a/src/file/format/toml.rs b/src/file/format/toml.rs
index af21fc78..19b78044 100644
--- a/src/file/format/toml.rs
+++ b/src/file/format/toml.rs
@@ -1,20 +1,16 @@
 use std::error::Error;
 
+use crate::format;
 use crate::map::Map;
-use crate::value::{Value, ValueKind};
+use crate::value::Value;
 
 pub fn parse(
     uri: Option<&String>,
     text: &str,
 ) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
     // Parse a TOML value from the provided text
-    // TODO: Have a proper error fire if the root of a file is ever not a Table
     let value = from_toml_value(uri, &toml::from_str(text)?);
-    match value.kind {
-        ValueKind::Table(map) => Ok(map),
-
-        _ => Ok(Map::new()),
-    }
+    format::extract_root_table(uri, value)
 }
 
 fn from_toml_value(uri: Option<&String>, value: &toml::Value) -> Value {
diff --git a/src/file/format/yaml.rs b/src/file/format/yaml.rs
index c9c8a224..b35ba4d9 100644
--- a/src/file/format/yaml.rs
+++ b/src/file/format/yaml.rs
@@ -4,6 +4,7 @@ use std::mem;
 
 use yaml_rust as yaml;
 
+use crate::format;
 use crate::map::Map;
 use crate::value::{Value, ValueKind};
 
@@ -21,13 +22,8 @@ pub fn parse(
         }
     };
 
-    // TODO: Have a proper error fire if the root of a file is ever not a Table
     let value = from_yaml_value(uri, &root)?;
-    match value.kind {
-        ValueKind::Table(map) => Ok(map),
-
-        _ => Ok(Map::new()),
-    }
+    format::extract_root_table(uri, value)
 }
 
 fn from_yaml_value(
diff --git a/src/format.rs b/src/format.rs
index ab9e4fa2..3d1ca335 100644
--- a/src/format.rs
+++ b/src/format.rs
@@ -1,6 +1,8 @@
 use std::error::Error;
 
-use crate::{map::Map, value::Value};
+use crate::error::{ConfigError, Unexpected};
+use crate::map::Map;
+use crate::value::{Value, ValueKind};
 
 /// Describes a format of configuration source data
 ///
@@ -21,3 +23,24 @@ pub trait Format {
         text: &str,
     ) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>>;
 }
+
+// Have a proper error fire if the root of a file is ever not a Table
+pub fn extract_root_table(
+    uri: Option<&String>,
+    value: Value,
+) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
+    match value.kind {
+        ValueKind::Table(map) => Ok(map),
+        ValueKind::Nil => Err(Unexpected::Unit),
+        ValueKind::Array(_value) => Err(Unexpected::Seq),
+        ValueKind::Boolean(value) => Err(Unexpected::Bool(value)),
+        ValueKind::I64(value) => Err(Unexpected::I64(value)),
+        ValueKind::I128(value) => Err(Unexpected::I128(value)),
+        ValueKind::U64(value) => Err(Unexpected::U64(value)),
+        ValueKind::U128(value) => Err(Unexpected::U128(value)),
+        ValueKind::Float(value) => Err(Unexpected::Float(value)),
+        ValueKind::String(value) => Err(Unexpected::Str(value)),
+    }
+    .map_err(|err| ConfigError::invalid_root(uri, err))
+    .map_err(|err| Box::new(err) as Box<dyn Error + Send + Sync>)
+}