Metadata can track used keys and unused keys
diff --git a/mapstructure.go b/mapstructure.go
index d2cd7a3..3a01f0e 100644
--- a/mapstructure.go
+++ b/mapstructure.go
@@ -49,7 +49,7 @@
 func Decode(m interface{}, rawVal interface{}) error {
 	config := &DecoderConfig{
 		Metadata: nil,
-		Result: rawVal,
+		Result:   rawVal,
 	}
 
 	decoder, err := NewDecoder(config)
@@ -106,27 +106,36 @@
 		k = reflect.Uint
 	}
 
+	var err error
 	switch k {
 	case reflect.Bool:
 		fallthrough
 	case reflect.Interface:
 		fallthrough
 	case reflect.String:
-		return d.decodeBasic(name, data, val)
+		err = d.decodeBasic(name, data, val)
 	case reflect.Int:
 		fallthrough
 	case reflect.Uint:
-		return d.decodeInt(name, data, val)
+		err = d.decodeInt(name, data, val)
 	case reflect.Struct:
-		return d.decodeStruct(name, data, val)
+		err = d.decodeStruct(name, data, val)
 	case reflect.Map:
-		return d.decodeMap(name, data, val)
+		err = d.decodeMap(name, data, val)
 	case reflect.Slice:
-		return d.decodeSlice(name, data, val)
+		err = d.decodeSlice(name, data, val)
+	default:
+		// If we reached this point then we weren't able to decode it
+		return fmt.Errorf("%s: unsupported type: %s", name, k)
 	}
 
-	// If we reached this point then we weren't able to decode it
-	return fmt.Errorf("%s: unsupported type: %s", name, k)
+	// If we reached here, then we successfully decoded SOMETHING, so
+	// mark the key as used if we're tracking metadata.
+	if d.config.Metadata != nil && name != "" {
+		d.config.Metadata.Keys = append(d.config.Metadata.Keys, name)
+	}
+
+	return err
 }
 
 // This decodes a basic type (bool, int, string, etc.) and sets the
@@ -294,8 +303,14 @@
 			name, dataValType.Key().Kind())
 	}
 
-	errors := make([]string, 0)
+	dataValKeys := make(map[reflect.Value]struct{})
+	dataValKeysUnused := make(map[interface{}]struct{})
+	for _, dataValKey := range dataVal.MapKeys() {
+		dataValKeys[dataValKey] = struct{}{}
+		dataValKeysUnused[dataValKey.Interface()] = struct{}{}
+	}
 
+	errors := make([]string, 0)
 	valType := val.Type()
 	for i := 0; i < valType.NumField(); i++ {
 		fieldType := valType.Field(i)
@@ -306,15 +321,17 @@
 			fieldName = tagValue
 		}
 
-		rawMapVal := dataVal.MapIndex(reflect.ValueOf(fieldName))
+		rawMapKey := reflect.ValueOf(fieldName)
+		rawMapVal := dataVal.MapIndex(rawMapKey)
 		if !rawMapVal.IsValid() {
 			// Do a slower search by iterating over each key and
 			// doing case-insensitive search.
-			for _, dataKeyVal := range dataVal.MapKeys() {
-				mK := dataKeyVal.Interface().(string)
+			for dataValKey, _ := range dataValKeys {
+				mK := dataValKey.Interface().(string)
 
 				if strings.EqualFold(mK, fieldName) {
-					rawMapVal = dataVal.MapIndex(dataKeyVal)
+					rawMapKey = dataValKey
+					rawMapVal = dataVal.MapIndex(dataValKey)
 					break
 				}
 			}
@@ -326,6 +343,9 @@
 			}
 		}
 
+		// Delete the key we're using from the unused map so we stop tracking
+		delete(dataValKeysUnused, rawMapKey.Interface())
+
 		field := val.Field(i)
 		if !field.IsValid() {
 			// This should never happen
@@ -353,5 +373,17 @@
 		return &Error{errors}
 	}
 
+	// Add the unused keys to the list of unused keys if we're tracking metadata
+	if d.config.Metadata != nil {
+		for rawKey, _ := range dataValKeysUnused {
+			key := rawKey.(string)
+			if name != "" {
+				key = fmt.Sprintf("%s.%s", name, key)
+			}
+
+			d.config.Metadata.Unused = append(d.config.Metadata.Unused, key)
+		}
+	}
+
 	return nil
 }
diff --git a/mapstructure_test.go b/mapstructure_test.go
index 4d664ed..cc1f249 100644
--- a/mapstructure_test.go
+++ b/mapstructure_test.go
@@ -1,6 +1,9 @@
 package mapstructure
 
-import "testing"
+import (
+	"reflect"
+	"testing"
+)
 
 type Basic struct {
 	Vstring string
@@ -343,6 +346,47 @@
 	}
 }
 
+func TestMetadata(t *testing.T) {
+	t.Parallel()
+
+	input := map[string]interface{}{
+		"vfoo": "foo",
+		"vbar": map[string]interface{}{
+			"vstring": "foo",
+			"Vuint":   42,
+			"foo":     "bar",
+		},
+		"bar": "nil",
+	}
+
+	var md Metadata
+	var result Nested
+	config := &DecoderConfig{
+		Metadata: &md,
+		Result:   &result,
+	}
+
+	decoder, err := NewDecoder(config)
+	if err != nil {
+		t.Fatalf("err: %s", err)
+	}
+
+	err = decoder.Decode(input)
+	if err != nil {
+		t.Fatalf("err: %s", err.Error())
+	}
+
+	expectedKeys := []string{"Vfoo", "Vbar.Vstring", "Vbar.Vuint", "Vbar"}
+	if !reflect.DeepEqual(md.Keys, expectedKeys) {
+		t.Fatalf("bad keys: %#v", md.Keys)
+	}
+
+	expectedUnused := []string{"Vbar.foo", "bar"}
+	if !reflect.DeepEqual(md.Unused, expectedUnused) {
+		t.Fatalf("bad unused: %#v", md.Unused)
+	}
+}
+
 func TestNonPtrValue(t *testing.T) {
 	t.Parallel()