Repository: open-telemetry/opentelemetry-go
Pull request #720 (2020-05-13 16:02:31)

Move core and key to kv package 
See #704 

This relates to #261 

tensorchen: This is the last step of core package refactoring. In this PR, core package will be completely eliminated.
jmacd: I will follow immediately with a removal for NewKey. This change is difficult to work with.

Patch:
diff --git a/api/core/key.go b/api/core/key.go
deleted file mode 100644
index fd8cc589..00000000
--- a/api/core/key.go
+++ /dev/null
@@ -1,391 +0,0 @@
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package core
-
-//go:generate stringer -type=ValueType
-
-import (
-	"encoding/json"
-	"fmt"
-	"strconv"
-	"unsafe"
-
-	"go.opentelemetry.io/otel/api/internal"
-)
-
-// Key represents the key part in key-value pairs. It's a string. The
-// allowed character set in the key depends on the use of the key.
-type Key string
-
-// KeyValue holds a key and value pair.
-type KeyValue struct {
-	Key   Key
-	Value Value
-}
-
-// ValueType describes the type of the data Value holds.
-type ValueType int
-
-// Value represents the value part in key-value pairs.
-type Value struct {
-	vtype    ValueType
-	numeric  uint64
-	stringly string
-	// TODO Lazy value type?
-}
-
-const (
-	INVALID ValueType = iota // No value.
-	BOOL                     // Boolean value, use AsBool() to get it.
-	INT32                    // 32 bit signed integral value, use AsInt32() to get it.
-	INT64                    // 64 bit signed integral value, use AsInt64() to get it.
-	UINT32                   // 32 bit unsigned integral value, use AsUint32() to get it.
-	UINT64                   // 64 bit unsigned integral value, use AsUint64() to get it.
-	FLOAT32                  // 32 bit floating point value, use AsFloat32() to get it.
-	FLOAT64                  // 64 bit floating point value, use AsFloat64() to get it.
-	STRING                   // String value, use AsString() to get it.
-)
-
-// Bool creates a BOOL Value.
-func Bool(v bool) Value {
-	return Value{
-		vtype:   BOOL,
-		numeric: internal.BoolToRaw(v),
-	}
-}
-
-// Int64 creates an INT64 Value.
-func Int64(v int64) Value {
-	return Value{
-		vtype:   INT64,
-		numeric: internal.Int64ToRaw(v),
-	}
-}
-
-// Uint64 creates a UINT64 Value.
-func Uint64(v uint64) Value {
-	return Value{
-		vtype:   UINT64,
-		numeric: internal.Uint64ToRaw(v),
-	}
-}
-
-// Float64 creates a FLOAT64 Value.
-func Float64(v float64) Value {
-	return Value{
-		vtype:   FLOAT64,
-		numeric: internal.Float64ToRaw(v),
-	}
-}
-
-// Int32 creates an INT32 Value.
-func Int32(v int32) Value {
-	return Value{
-		vtype:   INT32,
-		numeric: internal.Int32ToRaw(v),
-	}
-}
-
-// Uint32 creates a UINT32 Value.
-func Uint32(v uint32) Value {
-	return Value{
-		vtype:   UINT32,
-		numeric: internal.Uint32ToRaw(v),
-	}
-}
-
-// Float32 creates a FLOAT32 Value.
-func Float32(v float32) Value {
-	return Value{
-		vtype:   FLOAT32,
-		numeric: internal.Float32ToRaw(v),
-	}
-}
-
-// String creates a STRING Value.
-func String(v string) Value {
-	return Value{
-		vtype:    STRING,
-		stringly: v,
-	}
-}
-
-// Int creates either an INT32 or an INT64 Value, depending on whether
-// the int type is 32 or 64 bits wide.
-func Int(v int) Value {
-	if unsafe.Sizeof(v) == 4 {
-		return Int32(int32(v))
-	}
-	return Int64(int64(v))
-}
-
-// Uint creates either a UINT32 or a UINT64 Value, depending on
-// whether the uint type is 32 or 64 bits wide.
-func Uint(v uint) Value {
-	if unsafe.Sizeof(v) == 4 {
-		return Uint32(uint32(v))
-	}
-	return Uint64(uint64(v))
-}
-
-// Bool creates a KeyValue instance with a BOOL Value.
-//
-// If creating both key and a bool value at the same time, then
-// instead of calling core.Key(name).Bool(value) consider using a
-// convenience function provided by the api/key package -
-// key.Bool(name, value).
-func (k Key) Bool(v bool) KeyValue {
-	return KeyValue{
-		Key:   k,
-		Value: Bool(v),
-	}
-}
-
-// Int64 creates a KeyValue instance with an INT64 Value.
-//
-// If creating both key and an int64 value at the same time, then
-// instead of calling core.Key(name).Int64(value) consider using a
-// convenience function provided by the api/key package -
-// key.Int64(name, value).
-func (k Key) Int64(v int64) KeyValue {
-	return KeyValue{
-		Key:   k,
-		Value: Int64(v),
-	}
-}
-
-// Uint64 creates a KeyValue instance with a UINT64 Value.
-//
-// If creating both key and a uint64 value at the same time, then
-// instead of calling core.Key(name).Uint64(value) consider using a
-// convenience function provided by the api/key package -
-// key.Uint64(name, value).
-func (k Key) Uint64(v uint64) KeyValue {
-	return KeyValue{
-		Key:   k,
-		Value: Uint64(v),
-	}
-}
-
-// Float64 creates a KeyValue instance with a FLOAT64 Value.
-//
-// If creating both key and a float64 value at the same time, then
-// instead of calling core.Key(name).Float64(value) consider using a
-// convenience function provided by the api/key package -
-// key.Float64(name, value).
-func (k Key) Float64(v float64) KeyValue {
-	return KeyValue{
-		Key:   k,
-		Value: Float64(v),
-	}
-}
-
-// Int32 creates a KeyValue instance with an INT32 Value.
-//
-// If creating both key and an int32 value at the same time, then
-// instead of calling core.Key(name).Int32(value) consider using a
-// convenience function provided by the api/key package -
-// key.Int32(name, value).
-func (k Key) Int32(v int32) KeyValue {
-	return KeyValue{
-		Key:   k,
-		Value: Int32(v),
-	}
-}
-
-// Uint32 creates a KeyValue instance with a UINT32 Value.
-//
-// If creating both key and a uint32 value at the same time, then
-// instead of calling core.Key(name).Uint32(value) consider using a
-// convenience function provided by the api/key package -
-// key.Uint32(name, value).
-func (k Key) Uint32(v uint32) KeyValue {
-	return KeyValue{
-		Key:   k,
-		Value: Uint32(v),
-	}
-}
-
-// Float32 creates a KeyValue instance with a FLOAT32 Value.
-//
-// If creating both key and a float32 value at the same time, then
-// instead of calling core.Key(name).Float32(value) consider using a
-// convenience function provided by the api/key package -
-// key.Float32(name, value).
-func (k Key) Float32(v float32) KeyValue {
-	return KeyValue{
-		Key:   k,
-		Value: Float32(v),
-	}
-}
-
-// String creates a KeyValue instance with a STRING Value.
-//
-// If creating both key and a string value at the same time, then
-// instead of calling core.Key(name).String(value) consider using a
-// convenience function provided by the api/key package -
-// key.String(name, value).
-func (k Key) String(v string) KeyValue {
-	return KeyValue{
-		Key:   k,
-		Value: String(v),
-	}
-}
-
-// Int creates a KeyValue instance with either an INT32 or an INT64
-// Value, depending on whether the int type is 32 or 64 bits wide.
-//
-// If creating both key and an int value at the same time, then
-// instead of calling core.Key(name).Int(value) consider using a
-// convenience function provided by the api/key package -
-// key.Int(name, value).
-func (k Key) Int(v int) KeyValue {
-	return KeyValue{
-		Key:   k,
-		Value: Int(v),
-	}
-}
-
-// Uint creates a KeyValue instance with either a UINT32 or a UINT64
-// Value, depending on whether the uint type is 32 or 64 bits wide.
-//
-// If creating both key and a uint value at the same time, then
-// instead of calling core.Key(name).Uint(value) consider using a
-// convenience function provided by the api/key package -
-// key.Uint(name, value).
-func (k Key) Uint(v uint) KeyValue {
-	return KeyValue{
-		Key:   k,
-		Value: Uint(v),
-	}
-}
-
-// Defined returns true for non-empty keys.
-func (k Key) Defined() bool {
-	return len(k) != 0
-}
-
-// Type returns a type of the Value.
-func (v Value) Type() ValueType {
-	return v.vtype
-}
-
-// AsBool returns the bool value. Make sure that the Value's type is
-// BOOL.
-func (v Value) AsBool() bool {
-	return internal.RawToBool(v.numeric)
-}
-
-// AsInt32 returns the int32 value. Make sure that the Value's type is
-// INT32.
-func (v Value) AsInt32() int32 {
-	return internal.RawToInt32(v.numeric)
-}
-
-// AsInt64 returns the int64 value. Make sure that the Value's type is
-// INT64.
-func (v Value) AsInt64() int64 {
-	return internal.RawToInt64(v.numeric)
-}
-
-// AsUint32 returns the uint32 value. Make sure that the Value's type
-// is UINT32.
-func (v Value) AsUint32() uint32 {
-	return internal.RawToUint32(v.numeric)
-}
-
-// AsUint64 returns the uint64 value. Make sure that the Value's type is
-// UINT64.
-func (v Value) AsUint64() uint64 {
-	return internal.RawToUint64(v.numeric)
-}
-
-// AsFloat32 returns the float32 value. Make sure that the Value's
-// type is FLOAT32.
-func (v Value) AsFloat32() float32 {
-	return internal.RawToFloat32(v.numeric)
-}
-
-// AsFloat64 returns the float64 value. Make sure that the Value's
-// type is FLOAT64.
-func (v Value) AsFloat64() float64 {
-	return internal.RawToFloat64(v.numeric)
-}
-
-// AsString returns the string value. Make sure that the Value's type
-// is STRING.
-func (v Value) AsString() string {
-	return v.stringly
-}
-
-type unknownValueType struct{}
-
-// AsInterface returns Value's data as interface{}.
-func (v Value) AsInterface() interface{} {
-	switch v.Type() {
-	case BOOL:
-		return v.AsBool()
-	case INT32:
-		return v.AsInt32()
-	case INT64:
-		return v.AsInt64()
-	case UINT32:
-		return v.AsUint32()
-	case UINT64:
-		return v.AsUint64()
-	case FLOAT32:
-		return v.AsFloat32()
-	case FLOAT64:
-		return v.AsFloat64()
-	case STRING:
-		return v.stringly
-	}
-	return unknownValueType{}
-}
-
-// Emit returns a string representation of Value's data.
-func (v Value) Emit() string {
-	switch v.Type() {
-	case BOOL:
-		return strconv.FormatBool(v.AsBool())
-	case INT32:
-		return strconv.FormatInt(int64(v.AsInt32()), 10)
-	case INT64:
-		return strconv.FormatInt(v.AsInt64(), 10)
-	case UINT32:
-		return strconv.FormatUint(uint64(v.AsUint32()), 10)
-	case UINT64:
-		return strconv.FormatUint(v.AsUint64(), 10)
-	case FLOAT32:
-		return fmt.Sprint(v.AsFloat32())
-	case FLOAT64:
-		return fmt.Sprint(v.AsFloat64())
-	case STRING:
-		return v.stringly
-	default:
-		return "unknown"
-	}
-}
-
-// MarshalJSON returns the JSON encoding of the Value.
-func (v Value) MarshalJSON() ([]byte, error) {
-	var jsonVal struct {
-		Type  string
-		Value interface{}
-	}
-	jsonVal.Type = v.Type().String()
-	jsonVal.Value = v.AsInterface()
-	return json.Marshal(jsonVal)
-}
diff --git a/api/core/valuetype_string.go b/api/core/valuetype_string.go
deleted file mode 100644
index 35d2175c..00000000
--- a/api/core/valuetype_string.go
+++ /dev/null
@@ -1,31 +0,0 @@
-// Code generated by "stringer -type=ValueType"; DO NOT EDIT.
-
-package core
-
-import "strconv"
-
-func _() {
-	// An "invalid array index" compiler error signifies that the constant values have changed.
-	// Re-run the stringer command to generate them again.
-	var x [1]struct{}
-	_ = x[INVALID-0]
-	_ = x[BOOL-1]
-	_ = x[INT32-2]
-	_ = x[INT64-3]
-	_ = x[UINT32-4]
-	_ = x[UINT64-5]
-	_ = x[FLOAT32-6]
-	_ = x[FLOAT64-7]
-	_ = x[STRING-8]
-}
-
-const _ValueType_name = "INVALIDBOOLINT32INT64UINT32UINT64FLOAT32FLOAT64STRING"
-
-var _ValueType_index = [...]uint8{0, 7, 11, 16, 21, 27, 33, 40, 47, 53}
-
-func (i ValueType) String() string {
-	if i < 0 || i >= ValueType(len(_ValueType_index)-1) {
-		return "ValueType(" + strconv.FormatInt(int64(i), 10) + ")"
-	}
-	return _ValueType_name[_ValueType_index[i]:_ValueType_index[i+1]]
-}
diff --git a/api/correlation/context.go b/api/correlation/context.go
index aa83ac4e..15545206 100644
--- a/api/correlation/context.go
+++ b/api/correlation/context.go
@@ -17,7 +17,7 @@ package correlation
 import (
 	"context"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 type correlationsType struct{}
@@ -150,7 +150,7 @@ func ContextWithMap(ctx context.Context, m Map) context.Context {
 
 // NewContext returns a context with the map from passed context
 // updated with the passed key-value pairs.
-func NewContext(ctx context.Context, keyvalues ...core.KeyValue) context.Context {
+func NewContext(ctx context.Context, keyvalues ...kv.KeyValue) context.Context {
 	return ContextWithMap(ctx, MapFromContext(ctx).Apply(MapUpdate{
 		MultiKV: keyvalues,
 	}))
diff --git a/api/correlation/correlation_context_propagator.go b/api/correlation/correlation_context_propagator.go
index 3ae2b931..8cee2420 100644
--- a/api/correlation/correlation_context_propagator.go
+++ b/api/correlation/correlation_context_propagator.go
@@ -19,8 +19,7 @@ import (
 	"net/url"
 	"strings"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/propagation"
 )
 
@@ -44,7 +43,7 @@ func (CorrelationContext) Inject(ctx context.Context, supplier propagation.HTTPS
 	correlationCtx := MapFromContext(ctx)
 	firstIter := true
 	var headerValueBuilder strings.Builder
-	correlationCtx.Foreach(func(kv core.KeyValue) bool {
+	correlationCtx.Foreach(func(kv kv.KeyValue) bool {
 		if !firstIter {
 			headerValueBuilder.WriteRune(',')
 		}
@@ -68,7 +67,7 @@ func (CorrelationContext) Extract(ctx context.Context, supplier propagation.HTTP
 	}
 
 	contextValues := strings.Split(correlationContext, ",")
-	keyValues := make([]core.KeyValue, 0, len(contextValues))
+	keyValues := make([]kv.KeyValue, 0, len(contextValues))
 	for _, contextValue := range contextValues {
 		valueAndProps := strings.Split(contextValue, ";")
 		if len(valueAndProps) < 1 {
@@ -98,7 +97,7 @@ func (CorrelationContext) Extract(ctx context.Context, supplier propagation.HTTP
 			trimmedValueWithProps.WriteString(prop)
 		}
 
-		keyValues = append(keyValues, key.New(trimmedName).String(trimmedValueWithProps.String()))
+		keyValues = append(keyValues, kv.NewKey(trimmedName).String(trimmedValueWithProps.String()))
 	}
 	return ContextWithMap(ctx, NewMap(MapUpdate{
 		MultiKV: keyValues,
diff --git a/api/correlation/map.go b/api/correlation/map.go
index 79a4f186..93e92eed 100644
--- a/api/correlation/map.go
+++ b/api/correlation/map.go
@@ -15,11 +15,12 @@
 package correlation
 
 import (
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
+	"go.opentelemetry.io/otel/api/kv/value"
 )
 
-type rawMap map[core.Key]core.Value
-type keySet map[core.Key]struct{}
+type rawMap map[kv.Key]value.Value
+type keySet map[kv.Key]struct{}
 
 // Map is an immutable storage for correlations.
 type Map struct {
@@ -32,18 +33,18 @@ type MapUpdate struct {
 	// DropSingleK contains a single key to be dropped from
 	// correlations. Use this to avoid an overhead of a slice
 	// allocation if there is only one key to drop.
-	DropSingleK core.Key
+	DropSingleK kv.Key
 	// DropMultiK contains all the keys to be dropped from
 	// correlations.
-	DropMultiK []core.Key
+	DropMultiK []kv.Key
 
 	// SingleKV contains a single key-value pair to be added to
 	// correlations. Use this to avoid an overhead of a slice
 	// allocation if there is only one key-value pair to add.
-	SingleKV core.KeyValue
+	SingleKV kv.KeyValue
 	// MultiKV contains all the key-value pairs to be added to
 	// correlations.
-	MultiKV []core.KeyValue
+	MultiKV []kv.KeyValue
 }
 
 func newMap(raw rawMap) Map {
@@ -101,7 +102,7 @@ func getModificationSets(update MapUpdate) (delSet, addSet keySet) {
 		deletionsCount++
 	}
 	if deletionsCount > 0 {
-		delSet = make(map[core.Key]struct{}, deletionsCount)
+		delSet = make(map[kv.Key]struct{}, deletionsCount)
 		for _, k := range update.DropMultiK {
 			delSet[k] = struct{}{}
 		}
@@ -115,7 +116,7 @@ func getModificationSets(update MapUpdate) (delSet, addSet keySet) {
 		additionsCount++
 	}
 	if additionsCount > 0 {
-		addSet = make(map[core.Key]struct{}, additionsCount)
+		addSet = make(map[kv.Key]struct{}, additionsCount)
 		for _, k := range update.MultiKV {
 			addSet[k.Key] = struct{}{}
 		}
@@ -146,14 +147,14 @@ func getNewMapSize(m rawMap, delSet, addSet keySet) int {
 
 // Value gets a value from correlations map and returns a boolean
 // value indicating whether the key exist in the map.
-func (m Map) Value(k core.Key) (core.Value, bool) {
+func (m Map) Value(k kv.Key) (value.Value, bool) {
 	value, ok := m.m[k]
 	return value, ok
 }
 
 // HasValue returns a boolean value indicating whether the key exist
 // in the map.
-func (m Map) HasValue(k core.Key) bool {
+func (m Map) HasValue(k kv.Key) bool {
 	_, has := m.Value(k)
 	return has
 }
@@ -166,9 +167,9 @@ func (m Map) Len() int {
 // Foreach calls a passed callback once on each key-value pair until
 // all the key-value pairs of the map were iterated or the callback
 // returns false, whichever happens first.
-func (m Map) Foreach(f func(kv core.KeyValue) bool) {
+func (m Map) Foreach(f func(kv kv.KeyValue) bool) {
 	for k, v := range m.m {
-		if !f(core.KeyValue{
+		if !f(kv.KeyValue{
 			Key:   k,
 			Value: v,
 		}) {
diff --git a/api/global/internal/meter.go b/api/global/internal/meter.go
index df75d3ae..a820a1f4 100644
--- a/api/global/internal/meter.go
+++ b/api/global/internal/meter.go
@@ -20,7 +20,7 @@ import (
 	"sync/atomic"
 	"unsafe"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 	"go.opentelemetry.io/otel/api/metric/registry"
 )
@@ -85,7 +85,7 @@ type asyncImpl struct {
 
 	instrument
 
-	callback func(func(metric.Number, []core.KeyValue))
+	callback func(func(metric.Number, []kv.KeyValue))
 }
 
 // SyncImpler is implemented by all of the sync metric
@@ -104,7 +104,7 @@ type syncHandle struct {
 	delegate unsafe.Pointer // (*metric.HandleImpl)
 
 	inst   *syncImpl
-	labels []core.KeyValue
+	labels []kv.KeyValue
 
 	initialize sync.Once
 }
@@ -219,7 +219,7 @@ func (inst *syncImpl) Implementation() interface{} {
 	return inst
 }
 
-func (inst *syncImpl) Bind(labels []core.KeyValue) metric.BoundSyncImpl {
+func (inst *syncImpl) Bind(labels []kv.KeyValue) metric.BoundSyncImpl {
 	if implPtr := (*metric.SyncImpl)(atomic.LoadPointer(&inst.delegate)); implPtr != nil {
 		return (*implPtr).Bind(labels)
 	}
@@ -245,7 +245,7 @@ func (bound *syncHandle) Unbind() {
 
 func (m *meterImpl) NewAsyncInstrument(
 	desc metric.Descriptor,
-	callback func(func(metric.Number, []core.KeyValue)),
+	callback func(func(metric.Number, []kv.KeyValue)),
 ) (metric.AsyncImpl, error) {
 
 	m.lock.Lock()
@@ -291,13 +291,13 @@ func (obs *asyncImpl) setDelegate(d metric.MeterImpl) {
 
 // Metric updates
 
-func (m *meterImpl) RecordBatch(ctx context.Context, labels []core.KeyValue, measurements ...metric.Measurement) {
+func (m *meterImpl) RecordBatch(ctx context.Context, labels []kv.KeyValue, measurements ...metric.Measurement) {
 	if delegatePtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); delegatePtr != nil {
 		(*delegatePtr).RecordBatch(ctx, labels, measurements...)
 	}
 }
 
-func (inst *syncImpl) RecordOne(ctx context.Context, number metric.Number, labels []core.KeyValue) {
+func (inst *syncImpl) RecordOne(ctx context.Context, number metric.Number, labels []kv.KeyValue) {
 	if instPtr := (*metric.SyncImpl)(atomic.LoadPointer(&inst.delegate)); instPtr != nil {
 		(*instPtr).RecordOne(ctx, number, labels)
 	}
diff --git a/api/key/doc.go b/api/key/doc.go
deleted file mode 100644
index a4387b1a..00000000
--- a/api/key/doc.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// This package provides convenience functions for creating keys and
-// key-value pairs.
-package key // import "go.opentelemetry.io/otel/api/key"
diff --git a/api/core/doc.go b/api/kv/doc.go
similarity index 93%
rename from api/core/doc.go
rename to api/kv/doc.go
index 34c4ecba..5261ec99 100644
--- a/api/core/doc.go
+++ b/api/kv/doc.go
@@ -17,4 +17,4 @@
 //
 // See the api/key package for convenience functions for creating keys
 // and key-value pairs.
-package core // import "go.opentelemetry.io/otel/api/core"
+package kv // import "go.opentelemetry.io/otel/api/kv"
diff --git a/api/kv/key.go b/api/kv/key.go
new file mode 100644
index 00000000..20285187
--- /dev/null
+++ b/api/kv/key.go
@@ -0,0 +1,165 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kv
+
+import (
+	"go.opentelemetry.io/otel/api/kv/value"
+)
+
+// Key represents the key part in key-value pairs. It's a string. The
+// allowed character set in the key depends on the use of the key.
+type Key string
+
+// NewKey creates a new key with a passed name.
+func NewKey(name string) Key {
+	return Key(name)
+}
+
+// Bool creates a KeyValue instance with a BOOL Value.
+//
+// If creating both key and a bool value at the same time, then
+// instead of calling kv.Key(name).Bool(value) consider using a
+// convenience function provided by the api/key package -
+// key.Bool(name, value).
+func (k Key) Bool(v bool) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: value.Bool(v),
+	}
+}
+
+// Int64 creates a KeyValue instance with an INT64 Value.
+//
+// If creating both key and an int64 value at the same time, then
+// instead of calling kv.Key(name).Int64(value) consider using a
+// convenience function provided by the api/key package -
+// key.Int64(name, value).
+func (k Key) Int64(v int64) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: value.Int64(v),
+	}
+}
+
+// Uint64 creates a KeyValue instance with a UINT64 Value.
+//
+// If creating both key and a uint64 value at the same time, then
+// instead of calling kv.Key(name).Uint64(value) consider using a
+// convenience function provided by the api/key package -
+// key.Uint64(name, value).
+func (k Key) Uint64(v uint64) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: value.Uint64(v),
+	}
+}
+
+// Float64 creates a KeyValue instance with a FLOAT64 Value.
+//
+// If creating both key and a float64 value at the same time, then
+// instead of calling kv.Key(name).Float64(value) consider using a
+// convenience function provided by the api/key package -
+// key.Float64(name, value).
+func (k Key) Float64(v float64) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: value.Float64(v),
+	}
+}
+
+// Int32 creates a KeyValue instance with an INT32 Value.
+//
+// If creating both key and an int32 value at the same time, then
+// instead of calling kv.Key(name).Int32(value) consider using a
+// convenience function provided by the api/key package -
+// key.Int32(name, value).
+func (k Key) Int32(v int32) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: value.Int32(v),
+	}
+}
+
+// Uint32 creates a KeyValue instance with a UINT32 Value.
+//
+// If creating both key and a uint32 value at the same time, then
+// instead of calling kv.Key(name).Uint32(value) consider using a
+// convenience function provided by the api/key package -
+// key.Uint32(name, value).
+func (k Key) Uint32(v uint32) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: value.Uint32(v),
+	}
+}
+
+// Float32 creates a KeyValue instance with a FLOAT32 Value.
+//
+// If creating both key and a float32 value at the same time, then
+// instead of calling kv.Key(name).Float32(value) consider using a
+// convenience function provided by the api/key package -
+// key.Float32(name, value).
+func (k Key) Float32(v float32) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: value.Float32(v),
+	}
+}
+
+// String creates a KeyValue instance with a STRING Value.
+//
+// If creating both key and a string value at the same time, then
+// instead of calling kv.Key(name).String(value) consider using a
+// convenience function provided by the api/key package -
+// key.String(name, value).
+func (k Key) String(v string) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: value.String(v),
+	}
+}
+
+// Int creates a KeyValue instance with either an INT32 or an INT64
+// Value, depending on whether the int type is 32 or 64 bits wide.
+//
+// If creating both key and an int value at the same time, then
+// instead of calling kv.Key(name).Int(value) consider using a
+// convenience function provided by the api/key package -
+// key.Int(name, value).
+func (k Key) Int(v int) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: value.Int(v),
+	}
+}
+
+// Uint creates a KeyValue instance with either a UINT32 or a UINT64
+// Value, depending on whether the uint type is 32 or 64 bits wide.
+//
+// If creating both key and a uint value at the same time, then
+// instead of calling kv.Key(name).Uint(value) consider using a
+// convenience function provided by the api/key package -
+// key.Uint(name, value).
+func (k Key) Uint(v uint) KeyValue {
+	return KeyValue{
+		Key:   k,
+		Value: value.Uint(v),
+	}
+}
+
+// Defined returns true for non-empty keys.
+func (k Key) Defined() bool {
+	return len(k) != 0
+}
diff --git a/api/key/key.go b/api/kv/kv.go
similarity index 73%
rename from api/key/key.go
rename to api/kv/kv.go
index 2e077394..f159b553 100644
--- a/api/key/key.go
+++ b/api/kv/kv.go
@@ -12,91 +12,92 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package key
+package kv
 
 import (
 	"fmt"
 	"reflect"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv/value"
 )
 
-// New creates a new key with a passed name.
-func New(name string) core.Key {
-	return core.Key(name)
+// KeyValue holds a key and value pair.
+type KeyValue struct {
+	Key   Key
+	Value value.Value
 }
 
 // Bool creates a new key-value pair with a passed name and a bool
 // value.
-func Bool(k string, v bool) core.KeyValue {
-	return New(k).Bool(v)
+func Bool(k string, v bool) KeyValue {
+	return NewKey(k).Bool(v)
 }
 
 // Int64 creates a new key-value pair with a passed name and an int64
 // value.
-func Int64(k string, v int64) core.KeyValue {
-	return New(k).Int64(v)
+func Int64(k string, v int64) KeyValue {
+	return NewKey(k).Int64(v)
 }
 
 // Uint64 creates a new key-value pair with a passed name and a uint64
 // value.
-func Uint64(k string, v uint64) core.KeyValue {
-	return New(k).Uint64(v)
+func Uint64(k string, v uint64) KeyValue {
+	return NewKey(k).Uint64(v)
 }
 
 // Float64 creates a new key-value pair with a passed name and a float64
 // value.
-func Float64(k string, v float64) core.KeyValue {
-	return New(k).Float64(v)
+func Float64(k string, v float64) KeyValue {
+	return NewKey(k).Float64(v)
 }
 
 // Int32 creates a new key-value pair with a passed name and an int32
 // value.
-func Int32(k string, v int32) core.KeyValue {
-	return New(k).Int32(v)
+func Int32(k string, v int32) KeyValue {
+	return NewKey(k).Int32(v)
 }
 
 // Uint32 creates a new key-value pair with a passed name and a uint32
 // value.
-func Uint32(k string, v uint32) core.KeyValue {
-	return New(k).Uint32(v)
+func Uint32(k string, v uint32) KeyValue {
+	return NewKey(k).Uint32(v)
 }
 
 // Float32 creates a new key-value pair with a passed name and a float32
 // value.
-func Float32(k string, v float32) core.KeyValue {
-	return New(k).Float32(v)
+func Float32(k string, v float32) KeyValue {
+	return NewKey(k).Float32(v)
 }
 
 // String creates a new key-value pair with a passed name and a string
 // value.
-func String(k, v string) core.KeyValue {
-	return New(k).String(v)
+func String(k, v string) KeyValue {
+	return NewKey(k).String(v)
 }
 
 // Stringer creates a new key-value pair with a passed name and a string
 // value generated by the passed Stringer interface.
-func Stringer(k string, v fmt.Stringer) core.KeyValue {
-	return New(k).String(v.String())
+func Stringer(k string, v fmt.Stringer) KeyValue {
+	return NewKey(k).String(v.String())
 }
 
 // Int creates a new key-value pair instance with a passed name and
 // either an int32 or an int64 value, depending on whether the int
 // type is 32 or 64 bits wide.
-func Int(k string, v int) core.KeyValue {
-	return New(k).Int(v)
+func Int(k string, v int) KeyValue {
+	return NewKey(k).Int(v)
 }
 
 // Uint creates a new key-value pair instance with a passed name and
 // either an uint32 or an uint64 value, depending on whether the uint
 // type is 32 or 64 bits wide.
-func Uint(k string, v uint) core.KeyValue {
-	return New(k).Uint(v)
+func Uint(k string, v uint) KeyValue {
+	return NewKey(k).Uint(v)
 }
 
 // Infer creates a new key-value pair instance with a passed name and
 // automatic type inference. This is slower, and not type-safe.
-func Infer(k string, value interface{}) core.KeyValue {
+func Infer(k string, value interface{}) KeyValue {
 	if value == nil {
 		return String(k, "<nil>")
 	}
diff --git a/api/kv/value/type_string.go b/api/kv/value/type_string.go
new file mode 100644
index 00000000..ae4b0032
--- /dev/null
+++ b/api/kv/value/type_string.go
@@ -0,0 +1,31 @@
+// Code generated by "stringer -type=Type"; DO NOT EDIT.
+
+package value
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[INVALID-0]
+	_ = x[BOOL-1]
+	_ = x[INT32-2]
+	_ = x[INT64-3]
+	_ = x[UINT32-4]
+	_ = x[UINT64-5]
+	_ = x[FLOAT32-6]
+	_ = x[FLOAT64-7]
+	_ = x[STRING-8]
+}
+
+const _Type_name = "INVALIDBOOLINT32INT64UINT32UINT64FLOAT32FLOAT64STRING"
+
+var _Type_index = [...]uint8{0, 7, 11, 16, 21, 27, 33, 40, 47, 53}
+
+func (i Type) String() string {
+	if i < 0 || i >= Type(len(_Type_index)-1) {
+		return "Type(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _Type_name[_Type_index[i]:_Type_index[i+1]]
+}
diff --git a/api/kv/value/value.go b/api/kv/value/value.go
new file mode 100644
index 00000000..0e52da19
--- /dev/null
+++ b/api/kv/value/value.go
@@ -0,0 +1,244 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package value
+
+import (
+	"encoding/json"
+	"fmt"
+	"strconv"
+	"unsafe"
+
+	"go.opentelemetry.io/otel/api/internal"
+)
+
+//go:generate stringer -type=Type
+
+// Type describes the type of the data Value holds.
+type Type int
+
+// Value represents the value part in key-value pairs.
+type Value struct {
+	vtype    Type
+	numeric  uint64
+	stringly string
+	// TODO Lazy value type?
+}
+
+const (
+	INVALID Type = iota // No value.
+	BOOL                // Boolean value, use AsBool() to get it.
+	INT32               // 32 bit signed integral value, use AsInt32() to get it.
+	INT64               // 64 bit signed integral value, use AsInt64() to get it.
+	UINT32              // 32 bit unsigned integral value, use AsUint32() to get it.
+	UINT64              // 64 bit unsigned integral value, use AsUint64() to get it.
+	FLOAT32             // 32 bit floating point value, use AsFloat32() to get it.
+	FLOAT64             // 64 bit floating point value, use AsFloat64() to get it.
+	STRING              // String value, use AsString() to get it.
+)
+
+// Bool creates a BOOL Value.
+func Bool(v bool) Value {
+	return Value{
+		vtype:   BOOL,
+		numeric: internal.BoolToRaw(v),
+	}
+}
+
+// Int64 creates an INT64 Value.
+func Int64(v int64) Value {
+	return Value{
+		vtype:   INT64,
+		numeric: internal.Int64ToRaw(v),
+	}
+}
+
+// Uint64 creates a UINT64 Value.
+func Uint64(v uint64) Value {
+	return Value{
+		vtype:   UINT64,
+		numeric: internal.Uint64ToRaw(v),
+	}
+}
+
+// Float64 creates a FLOAT64 Value.
+func Float64(v float64) Value {
+	return Value{
+		vtype:   FLOAT64,
+		numeric: internal.Float64ToRaw(v),
+	}
+}
+
+// Int32 creates an INT32 Value.
+func Int32(v int32) Value {
+	return Value{
+		vtype:   INT32,
+		numeric: internal.Int32ToRaw(v),
+	}
+}
+
+// Uint32 creates a UINT32 Value.
+func Uint32(v uint32) Value {
+	return Value{
+		vtype:   UINT32,
+		numeric: internal.Uint32ToRaw(v),
+	}
+}
+
+// Float32 creates a FLOAT32 Value.
+func Float32(v float32) Value {
+	return Value{
+		vtype:   FLOAT32,
+		numeric: internal.Float32ToRaw(v),
+	}
+}
+
+// String creates a STRING Value.
+func String(v string) Value {
+	return Value{
+		vtype:    STRING,
+		stringly: v,
+	}
+}
+
+// Int creates either an INT32 or an INT64 Value, depending on whether
+// the int type is 32 or 64 bits wide.
+func Int(v int) Value {
+	if unsafe.Sizeof(v) == 4 {
+		return Int32(int32(v))
+	}
+	return Int64(int64(v))
+}
+
+// Uint creates either a UINT32 or a UINT64 Value, depending on
+// whether the uint type is 32 or 64 bits wide.
+func Uint(v uint) Value {
+	if unsafe.Sizeof(v) == 4 {
+		return Uint32(uint32(v))
+	}
+	return Uint64(uint64(v))
+}
+
+// Type returns a type of the Value.
+func (v Value) Type() Type {
+	return v.vtype
+}
+
+// AsBool returns the bool value. Make sure that the Value's type is
+// BOOL.
+func (v Value) AsBool() bool {
+	return internal.RawToBool(v.numeric)
+}
+
+// AsInt32 returns the int32 value. Make sure that the Value's type is
+// INT32.
+func (v Value) AsInt32() int32 {
+	return internal.RawToInt32(v.numeric)
+}
+
+// AsInt64 returns the int64 value. Make sure that the Value's type is
+// INT64.
+func (v Value) AsInt64() int64 {
+	return internal.RawToInt64(v.numeric)
+}
+
+// AsUint32 returns the uint32 value. Make sure that the Value's type
+// is UINT32.
+func (v Value) AsUint32() uint32 {
+	return internal.RawToUint32(v.numeric)
+}
+
+// AsUint64 returns the uint64 value. Make sure that the Value's type is
+// UINT64.
+func (v Value) AsUint64() uint64 {
+	return internal.RawToUint64(v.numeric)
+}
+
+// AsFloat32 returns the float32 value. Make sure that the Value's
+// type is FLOAT32.
+func (v Value) AsFloat32() float32 {
+	return internal.RawToFloat32(v.numeric)
+}
+
+// AsFloat64 returns the float64 value. Make sure that the Value's
+// type is FLOAT64.
+func (v Value) AsFloat64() float64 {
+	return internal.RawToFloat64(v.numeric)
+}
+
+// AsString returns the string value. Make sure that the Value's type
+// is STRING.
+func (v Value) AsString() string {
+	return v.stringly
+}
+
+type unknownValueType struct{}
+
+// AsInterface returns Value's data as interface{}.
+func (v Value) AsInterface() interface{} {
+	switch v.Type() {
+	case BOOL:
+		return v.AsBool()
+	case INT32:
+		return v.AsInt32()
+	case INT64:
+		return v.AsInt64()
+	case UINT32:
+		return v.AsUint32()
+	case UINT64:
+		return v.AsUint64()
+	case FLOAT32:
+		return v.AsFloat32()
+	case FLOAT64:
+		return v.AsFloat64()
+	case STRING:
+		return v.stringly
+	}
+	return unknownValueType{}
+}
+
+// Emit returns a string representation of Value's data.
+func (v Value) Emit() string {
+	switch v.Type() {
+	case BOOL:
+		return strconv.FormatBool(v.AsBool())
+	case INT32:
+		return strconv.FormatInt(int64(v.AsInt32()), 10)
+	case INT64:
+		return strconv.FormatInt(v.AsInt64(), 10)
+	case UINT32:
+		return strconv.FormatUint(uint64(v.AsUint32()), 10)
+	case UINT64:
+		return strconv.FormatUint(v.AsUint64(), 10)
+	case FLOAT32:
+		return fmt.Sprint(v.AsFloat32())
+	case FLOAT64:
+		return fmt.Sprint(v.AsFloat64())
+	case STRING:
+		return v.stringly
+	default:
+		return "unknown"
+	}
+}
+
+// MarshalJSON returns the JSON encoding of the Value.
+func (v Value) MarshalJSON() ([]byte, error) {
+	var jsonVal struct {
+		Type  string
+		Value interface{}
+	}
+	jsonVal.Type = v.Type().String()
+	jsonVal.Value = v.AsInterface()
+	return json.Marshal(jsonVal)
+}
diff --git a/api/label/encoder.go b/api/label/encoder.go
index 949613a2..0c14ee52 100644
--- a/api/label/encoder.go
+++ b/api/label/encoder.go
@@ -19,7 +19,7 @@ import (
 	"sync"
 	"sync/atomic"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv/value"
 )
 
 type (
@@ -111,18 +111,18 @@ func (d *defaultLabelEncoder) Encode(iter Iterator) string {
 	buf.Reset()
 
 	for iter.Next() {
-		i, kv := iter.IndexedLabel()
+		i, keyValue := iter.IndexedLabel()
 		if i > 0 {
 			_, _ = buf.WriteRune(',')
 		}
-		copyAndEscape(buf, string(kv.Key))
+		copyAndEscape(buf, string(keyValue.Key))
 
 		_, _ = buf.WriteRune('=')
 
-		if kv.Value.Type() == core.STRING {
-			copyAndEscape(buf, kv.Value.AsString())
+		if keyValue.Value.Type() == value.STRING {
+			copyAndEscape(buf, keyValue.Value.AsString())
 		} else {
-			_, _ = buf.WriteString(kv.Value.Emit())
+			_, _ = buf.WriteString(keyValue.Value.Emit())
 		}
 	}
 	return buf.String()
diff --git a/api/label/iterator.go b/api/label/iterator.go
index ca25f29e..6b345d09 100644
--- a/api/label/iterator.go
+++ b/api/label/iterator.go
@@ -15,7 +15,7 @@
 package label
 
 import (
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 // Iterator allows iterating over the set of labels in order,
@@ -32,26 +32,26 @@ func (i *Iterator) Next() bool {
 	return i.idx < i.Len()
 }
 
-// Label returns current core.KeyValue. Must be called only after Next returns
+// Label returns current kv.KeyValue. Must be called only after Next returns
 // true.
-func (i *Iterator) Label() core.KeyValue {
+func (i *Iterator) Label() kv.KeyValue {
 	kv, _ := i.storage.Get(i.idx)
 	return kv
 }
 
 // Attribute is a synonym for Label().
-func (i *Iterator) Attribute() core.KeyValue {
+func (i *Iterator) Attribute() kv.KeyValue {
 	return i.Label()
 }
 
 // IndexedLabel returns current index and label. Must be called only
 // after Next returns true.
-func (i *Iterator) IndexedLabel() (int, core.KeyValue) {
+func (i *Iterator) IndexedLabel() (int, kv.KeyValue) {
 	return i.idx, i.Label()
 }
 
 // IndexedAttribute is a synonym for IndexedLabel().
-func (i *Iterator) IndexedAttribute() (int, core.KeyValue) {
+func (i *Iterator) IndexedAttribute() (int, kv.KeyValue) {
 	return i.IndexedLabel()
 }
 
@@ -63,13 +63,13 @@ func (i *Iterator) Len() int {
 // ToSlice is a convenience function that creates a slice of labels
 // from the passed iterator. The iterator is set up to start from the
 // beginning before creating the slice.
-func (i *Iterator) ToSlice() []core.KeyValue {
+func (i *Iterator) ToSlice() []kv.KeyValue {
 	l := i.Len()
 	if l == 0 {
 		return nil
 	}
 	i.idx = -1
-	slice := make([]core.KeyValue, 0, l)
+	slice := make([]kv.KeyValue, 0, l)
 	for i.Next() {
 		slice = append(slice, i.Label())
 	}
diff --git a/api/label/set.go b/api/label/set.go
index 8533c571..5b39287f 100644
--- a/api/label/set.go
+++ b/api/label/set.go
@@ -20,7 +20,9 @@ import (
 	"sort"
 	"sync"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv/value"
+
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 type (
@@ -43,7 +45,7 @@ type (
 		encoded  [maxConcurrentEncoders]string
 	}
 
-	// Distinct wraps a variable-size array of `core.KeyValue`,
+	// Distinct wraps a variable-size array of `kv.KeyValue`,
 	// constructed with keys in sorted order.  This can be used as
 	// a map key or for equality checking between Sets.
 	Distinct struct {
@@ -51,22 +53,22 @@ type (
 	}
 
 	// Sortable implements `sort.Interface`, used for sorting
-	// `core.KeyValue`.  This is an exported type to support a
+	// `kv.KeyValue`.  This is an exported type to support a
 	// memory optimization.  A pointer to one of these is needed
 	// for the call to `sort.Stable()`, which the caller may
 	// provide in order to avoid an allocation.  See
 	// `NewSetWithSortable()`.
-	Sortable []core.KeyValue
+	Sortable []kv.KeyValue
 )
 
 var (
 	// keyValueType is used in `computeDistinctReflect`.
-	keyValueType = reflect.TypeOf(core.KeyValue{})
+	keyValueType = reflect.TypeOf(kv.KeyValue{})
 
 	// emptySet is returned for empty label sets.
 	emptySet = &Set{
 		equivalent: Distinct{
-			iface: [0]core.KeyValue{},
+			iface: [0]kv.KeyValue{},
 		},
 	}
 )
@@ -96,44 +98,44 @@ func (l *Set) Len() int {
 }
 
 // Get returns the KeyValue at ordered position `idx` in this set.
-func (l *Set) Get(idx int) (core.KeyValue, bool) {
+func (l *Set) Get(idx int) (kv.KeyValue, bool) {
 	if l == nil {
-		return core.KeyValue{}, false
+		return kv.KeyValue{}, false
 	}
 	value := l.equivalent.reflect()
 
 	if idx >= 0 && idx < value.Len() {
 		// Note: The Go compiler successfully avoids an allocation for
 		// the interface{} conversion here:
-		return value.Index(idx).Interface().(core.KeyValue), true
+		return value.Index(idx).Interface().(kv.KeyValue), true
 	}
 
-	return core.KeyValue{}, false
+	return kv.KeyValue{}, false
 }
 
 // Value returns the value of a specified key in this set.
-func (l *Set) Value(k core.Key) (core.Value, bool) {
+func (l *Set) Value(k kv.Key) (value.Value, bool) {
 	if l == nil {
-		return core.Value{}, false
+		return value.Value{}, false
 	}
-	value := l.equivalent.reflect()
-	vlen := value.Len()
+	rValue := l.equivalent.reflect()
+	vlen := rValue.Len()
 
 	idx := sort.Search(vlen, func(idx int) bool {
-		return value.Index(idx).Interface().(core.KeyValue).Key >= k
+		return rValue.Index(idx).Interface().(kv.KeyValue).Key >= k
 	})
 	if idx >= vlen {
-		return core.Value{}, false
+		return value.Value{}, false
 	}
-	kv := value.Index(idx).Interface().(core.KeyValue)
-	if k == kv.Key {
-		return kv.Value, true
+	keyValue := rValue.Index(idx).Interface().(kv.KeyValue)
+	if k == keyValue.Key {
+		return keyValue.Value, true
 	}
-	return core.Value{}, false
+	return value.Value{}, false
 }
 
 // HasValue tests whether a key is defined in this set.
-func (l *Set) HasValue(k core.Key) bool {
+func (l *Set) HasValue(k kv.Key) bool {
 	if l == nil {
 		return false
 	}
@@ -151,7 +153,7 @@ func (l *Set) Iter() Iterator {
 
 // ToSlice returns the set of labels belonging to this set, sorted,
 // where keys appear no more than once.
-func (l *Set) ToSlice() []core.KeyValue {
+func (l *Set) ToSlice() []kv.KeyValue {
 	iter := l.Iter()
 	return iter.ToSlice()
 }
@@ -226,7 +228,7 @@ func (l *Set) Encoded(encoder Encoder) string {
 //
 // Except for empty sets, this method adds an additional allocation
 // compared with a call to `NewSetWithSortable`.
-func NewSet(kvs ...core.KeyValue) Set {
+func NewSet(kvs ...kv.KeyValue) Set {
 	// Check for empty set.
 	if len(kvs) == 0 {
 		return Set{
@@ -258,7 +260,7 @@ func NewSet(kvs ...core.KeyValue) Set {
 //
 // The result maintains a cache of encoded labels, by label.EncoderID.
 // This value should not be copied after its first use.
-func NewSetWithSortable(kvs []core.KeyValue, tmp *Sortable) Set {
+func NewSetWithSortable(kvs []kv.KeyValue, tmp *Sortable) Set {
 	// Check for empty set.
 	if len(kvs) == 0 {
 		return Set{
@@ -299,7 +301,7 @@ func NewSetWithSortable(kvs []core.KeyValue, tmp *Sortable) Set {
 // computeDistinct returns a `Distinct` using either the fixed- or
 // reflect-oriented code path, depending on the size of the input.
 // The input slice is assumed to already be sorted and de-duplicated.
-func computeDistinct(kvs []core.KeyValue) Distinct {
+func computeDistinct(kvs []kv.KeyValue) Distinct {
 	iface := computeDistinctFixed(kvs)
 	if iface == nil {
 		iface = computeDistinctReflect(kvs)
@@ -311,46 +313,46 @@ func computeDistinct(kvs []core.KeyValue) Distinct {
 
 // computeDistinctFixed computes a `Distinct` for small slices.  It
 // returns nil if the input is too large for this code path.
-func computeDistinctFixed(kvs []core.KeyValue) interface{} {
+func computeDistinctFixed(kvs []kv.KeyValue) interface{} {
 	switch len(kvs) {
 	case 1:
-		ptr := new([1]core.KeyValue)
+		ptr := new([1]kv.KeyValue)
 		copy((*ptr)[:], kvs)
 		return *ptr
 	case 2:
-		ptr := new([2]core.KeyValue)
+		ptr := new([2]kv.KeyValue)
 		copy((*ptr)[:], kvs)
 		return *ptr
 	case 3:
-		ptr := new([3]core.KeyValue)
+		ptr := new([3]kv.KeyValue)
 		copy((*ptr)[:], kvs)
 		return *ptr
 	case 4:
-		ptr := new([4]core.KeyValue)
+		ptr := new([4]kv.KeyValue)
 		copy((*ptr)[:], kvs)
 		return *ptr
 	case 5:
-		ptr := new([5]core.KeyValue)
+		ptr := new([5]kv.KeyValue)
 		copy((*ptr)[:], kvs)
 		return *ptr
 	case 6:
-		ptr := new([6]core.KeyValue)
+		ptr := new([6]kv.KeyValue)
 		copy((*ptr)[:], kvs)
 		return *ptr
 	case 7:
-		ptr := new([7]core.KeyValue)
+		ptr := new([7]kv.KeyValue)
 		copy((*ptr)[:], kvs)
 		return *ptr
 	case 8:
-		ptr := new([8]core.KeyValue)
+		ptr := new([8]kv.KeyValue)
 		copy((*ptr)[:], kvs)
 		return *ptr
 	case 9:
-		ptr := new([9]core.KeyValue)
+		ptr := new([9]kv.KeyValue)
 		copy((*ptr)[:], kvs)
 		return *ptr
 	case 10:
-		ptr := new([10]core.KeyValue)
+		ptr := new([10]kv.KeyValue)
 		copy((*ptr)[:], kvs)
 		return *ptr
 	default:
@@ -360,10 +362,10 @@ func computeDistinctFixed(kvs []core.KeyValue) interface{} {
 
 // computeDistinctReflect computes a `Distinct` using reflection,
 // works for any size input.
-func computeDistinctReflect(kvs []core.KeyValue) interface{} {
+func computeDistinctReflect(kvs []kv.KeyValue) interface{} {
 	at := reflect.New(reflect.ArrayOf(len(kvs), keyValueType)).Elem()
-	for i, kv := range kvs {
-		*(at.Index(i).Addr().Interface().(*core.KeyValue)) = kv
+	for i, keyValue := range kvs {
+		*(at.Index(i).Addr().Interface().(*kv.KeyValue)) = keyValue
 	}
 	return at.Interface()
 }
diff --git a/api/metric/api.go b/api/metric/api.go
index d932a764..636a0fa0 100644
--- a/api/metric/api.go
+++ b/api/metric/api.go
@@ -19,7 +19,7 @@ package metric
 import (
 	"context"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/unit"
 )
 
@@ -145,7 +145,7 @@ type Meter struct {
 }
 
 // RecordBatch atomically records a batch of measurements.
-func (m Meter) RecordBatch(ctx context.Context, ls []core.KeyValue, ms ...Measurement) {
+func (m Meter) RecordBatch(ctx context.Context, ls []kv.KeyValue, ms ...Measurement) {
 	if m.impl == nil {
 		return
 	}
@@ -198,7 +198,7 @@ func (m Meter) RegisterInt64Observer(name string, callback Int64ObserverCallback
 	}
 	return wrapInt64ObserverInstrument(
 		m.newAsync(name, ObserverKind, Int64NumberKind, opts,
-			func(observe func(Number, []core.KeyValue)) {
+			func(observe func(Number, []kv.KeyValue)) {
 				callback(Int64ObserverResult{observe})
 			}))
 }
@@ -213,20 +213,20 @@ func (m Meter) RegisterFloat64Observer(name string, callback Float64ObserverCall
 	}
 	return wrapFloat64ObserverInstrument(
 		m.newAsync(name, ObserverKind, Float64NumberKind, opts,
-			func(observe func(Number, []core.KeyValue)) {
+			func(observe func(Number, []kv.KeyValue)) {
 				callback(Float64ObserverResult{observe})
 			}))
 }
 
 // Observe captures a single integer value from the associated
 // instrument callback, with the given labels.
-func (io Int64ObserverResult) Observe(value int64, labels ...core.KeyValue) {
+func (io Int64ObserverResult) Observe(value int64, labels ...kv.KeyValue) {
 	io.observe(NewInt64Number(value), labels)
 }
 
 // Observe captures a single floating point value from the associated
 // instrument callback, with the given labels.
-func (fo Float64ObserverResult) Observe(value float64, labels ...core.KeyValue) {
+func (fo Float64ObserverResult) Observe(value float64, labels ...kv.KeyValue) {
 	fo.observe(NewFloat64Number(value), labels)
 }
 
diff --git a/api/metric/common.go b/api/metric/common.go
index b9527722..dc61bfaa 100644
--- a/api/metric/common.go
+++ b/api/metric/common.go
@@ -18,7 +18,7 @@ import (
 	"context"
 	"errors"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 type syncInstrument struct {
@@ -35,7 +35,7 @@ type asyncInstrument struct {
 
 var ErrSDKReturnedNilImpl = errors.New("SDK returned a nil implementation")
 
-func (s syncInstrument) bind(labels []core.KeyValue) syncBoundInstrument {
+func (s syncInstrument) bind(labels []kv.KeyValue) syncBoundInstrument {
 	return newSyncBoundInstrument(s.instrument.Bind(labels))
 }
 
@@ -47,7 +47,7 @@ func (s syncInstrument) int64Measurement(value int64) Measurement {
 	return newMeasurement(s.instrument, NewInt64Number(value))
 }
 
-func (s syncInstrument) directRecord(ctx context.Context, number Number, labels []core.KeyValue) {
+func (s syncInstrument) directRecord(ctx context.Context, number Number, labels []kv.KeyValue) {
 	s.instrument.RecordOne(ctx, number, labels)
 }
 
diff --git a/api/metric/counter.go b/api/metric/counter.go
index bb3a824b..e9e73a35 100644
--- a/api/metric/counter.go
+++ b/api/metric/counter.go
@@ -17,7 +17,7 @@ package metric
 import (
 	"context"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 // Float64Counter is a metric that accumulates float64 values.
@@ -46,14 +46,14 @@ type BoundInt64Counter struct {
 
 // Bind creates a bound instrument for this counter. The labels are
 // associated with values recorded via subsequent calls to Record.
-func (c Float64Counter) Bind(labels ...core.KeyValue) (h BoundFloat64Counter) {
+func (c Float64Counter) Bind(labels ...kv.KeyValue) (h BoundFloat64Counter) {
 	h.syncBoundInstrument = c.bind(labels)
 	return
 }
 
 // Bind creates a bound instrument for this counter. The labels are
 // associated with values recorded via subsequent calls to Record.
-func (c Int64Counter) Bind(labels ...core.KeyValue) (h BoundInt64Counter) {
+func (c Int64Counter) Bind(labels ...kv.KeyValue) (h BoundInt64Counter) {
 	h.syncBoundInstrument = c.bind(labels)
 	return
 }
@@ -72,13 +72,13 @@ func (c Int64Counter) Measurement(value int64) Measurement {
 
 // Add adds the value to the counter's sum. The labels should contain
 // the keys and values to be associated with this value.
-func (c Float64Counter) Add(ctx context.Context, value float64, labels ...core.KeyValue) {
+func (c Float64Counter) Add(ctx context.Context, value float64, labels ...kv.KeyValue) {
 	c.directRecord(ctx, NewFloat64Number(value), labels)
 }
 
 // Add adds the value to the counter's sum. The labels should contain
 // the keys and values to be associated with this value.
-func (c Int64Counter) Add(ctx context.Context, value int64, labels ...core.KeyValue) {
+func (c Int64Counter) Add(ctx context.Context, value int64, labels ...kv.KeyValue) {
 	c.directRecord(ctx, NewInt64Number(value), labels)
 }
 
diff --git a/api/metric/measure.go b/api/metric/measure.go
index f6046958..11dd215e 100644
--- a/api/metric/measure.go
+++ b/api/metric/measure.go
@@ -17,7 +17,7 @@ package metric
 import (
 	"context"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 // Float64Measure is a metric that records float64 values.
@@ -46,14 +46,14 @@ type BoundInt64Measure struct {
 
 // Bind creates a bound instrument for this measure. The labels are
 // associated with values recorded via subsequent calls to Record.
-func (c Float64Measure) Bind(labels ...core.KeyValue) (h BoundFloat64Measure) {
+func (c Float64Measure) Bind(labels ...kv.KeyValue) (h BoundFloat64Measure) {
 	h.syncBoundInstrument = c.bind(labels)
 	return
 }
 
 // Bind creates a bound instrument for this measure. The labels are
 // associated with values recorded via subsequent calls to Record.
-func (c Int64Measure) Bind(labels ...core.KeyValue) (h BoundInt64Measure) {
+func (c Int64Measure) Bind(labels ...kv.KeyValue) (h BoundInt64Measure) {
 	h.syncBoundInstrument = c.bind(labels)
 	return
 }
@@ -73,14 +73,14 @@ func (c Int64Measure) Measurement(value int64) Measurement {
 // Record adds a new value to the list of measure's records. The
 // labels should contain the keys and values to be associated with
 // this value.
-func (c Float64Measure) Record(ctx context.Context, value float64, labels ...core.KeyValue) {
+func (c Float64Measure) Record(ctx context.Context, value float64, labels ...kv.KeyValue) {
 	c.directRecord(ctx, NewFloat64Number(value), labels)
 }
 
 // Record adds a new value to the list of measure's records. The
 // labels should contain the keys and values to be associated with
 // this value.
-func (c Int64Measure) Record(ctx context.Context, value int64, labels ...core.KeyValue) {
+func (c Int64Measure) Record(ctx context.Context, value int64, labels ...kv.KeyValue) {
 	c.directRecord(ctx, NewInt64Number(value), labels)
 }
 
diff --git a/api/metric/noop.go b/api/metric/noop.go
index 74dd5326..54d659c5 100644
--- a/api/metric/noop.go
+++ b/api/metric/noop.go
@@ -17,7 +17,7 @@ package metric
 import (
 	"context"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 type NoopProvider struct{}
@@ -50,9 +50,9 @@ func (noopBoundInstrument) RecordOne(context.Context, Number) {
 func (noopBoundInstrument) Unbind() {
 }
 
-func (NoopSync) Bind([]core.KeyValue) BoundSyncImpl {
+func (NoopSync) Bind([]kv.KeyValue) BoundSyncImpl {
 	return noopBoundInstrument{}
 }
 
-func (NoopSync) RecordOne(context.Context, Number, []core.KeyValue) {
+func (NoopSync) RecordOne(context.Context, Number, []kv.KeyValue) {
 }
diff --git a/api/metric/registry/registry.go b/api/metric/registry/registry.go
index f992b8ca..110ebe17 100644
--- a/api/metric/registry/registry.go
+++ b/api/metric/registry/registry.go
@@ -19,7 +19,7 @@ import (
 	"fmt"
 	"sync"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 )
 
@@ -54,7 +54,7 @@ func NewUniqueInstrumentMeterImpl(impl metric.MeterImpl) metric.MeterImpl {
 }
 
 // RecordBatch implements metric.MeterImpl.
-func (u *uniqueInstrumentMeterImpl) RecordBatch(ctx context.Context, labels []core.KeyValue, ms ...metric.Measurement) {
+func (u *uniqueInstrumentMeterImpl) RecordBatch(ctx context.Context, labels []kv.KeyValue, ms ...metric.Measurement) {
 	u.impl.RecordBatch(ctx, labels, ms...)
 }
 
@@ -125,7 +125,7 @@ func (u *uniqueInstrumentMeterImpl) NewSyncInstrument(descriptor metric.Descript
 // NewAsyncInstrument implements metric.MeterImpl.
 func (u *uniqueInstrumentMeterImpl) NewAsyncInstrument(
 	descriptor metric.Descriptor,
-	callback func(func(metric.Number, []core.KeyValue)),
+	callback func(func(metric.Number, []kv.KeyValue)),
 ) (metric.AsyncImpl, error) {
 	u.lock.Lock()
 	defer u.lock.Unlock()
diff --git a/api/metric/sdkhelpers.go b/api/metric/sdkhelpers.go
index ad881235..2024c2cc 100644
--- a/api/metric/sdkhelpers.go
+++ b/api/metric/sdkhelpers.go
@@ -17,14 +17,14 @@ package metric
 import (
 	"context"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 // MeterImpl is the interface an SDK must implement to supply a Meter
 // implementation.
 type MeterImpl interface {
 	// RecordBatch atomically records a batch of measurements.
-	RecordBatch(context.Context, []core.KeyValue, ...Measurement)
+	RecordBatch(context.Context, []kv.KeyValue, ...Measurement)
 
 	// NewSyncInstrument returns a newly constructed
 	// synchronous instrument implementation or an error, should
@@ -36,7 +36,7 @@ type MeterImpl interface {
 	// one occur.
 	NewAsyncInstrument(
 		descriptor Descriptor,
-		callback func(func(Number, []core.KeyValue)),
+		callback func(func(Number, []kv.KeyValue)),
 	) (AsyncImpl, error)
 }
 
@@ -59,10 +59,10 @@ type SyncImpl interface {
 
 	// Bind creates an implementation-level bound instrument,
 	// binding a label set with this instrument implementation.
-	Bind(labels []core.KeyValue) BoundSyncImpl
+	Bind(labels []kv.KeyValue) BoundSyncImpl
 
 	// RecordOne captures a single synchronous metric event.
-	RecordOne(ctx context.Context, number Number, labels []core.KeyValue)
+	RecordOne(ctx context.Context, number Number, labels []kv.KeyValue)
 }
 
 // BoundSyncImpl is the implementation-level interface to a
@@ -86,13 +86,13 @@ type AsyncImpl interface {
 // Int64ObserverResult is passed to an observer callback to capture
 // observations for one asynchronous integer metric instrument.
 type Int64ObserverResult struct {
-	observe func(Number, []core.KeyValue)
+	observe func(Number, []kv.KeyValue)
 }
 
 // Float64ObserverResult is passed to an observer callback to capture
 // observations for one asynchronous floating point metric instrument.
 type Float64ObserverResult struct {
-	observe func(Number, []core.KeyValue)
+	observe func(Number, []kv.KeyValue)
 }
 
 // Configure is a helper that applies all the options to a Config.
@@ -165,7 +165,7 @@ func wrapFloat64MeasureInstrument(syncInst SyncImpl, err error) (Float64Measure,
 }
 
 // newAsync constructs one new asynchronous instrument.
-func (m Meter) newAsync(name string, mkind Kind, nkind NumberKind, opts []Option, callback func(func(Number, []core.KeyValue))) (AsyncImpl, error) {
+func (m Meter) newAsync(name string, mkind Kind, nkind NumberKind, opts []Option, callback func(func(Number, []kv.KeyValue))) (AsyncImpl, error) {
 	if m.impl == nil {
 		return NoopAsync{}, nil
 	}
diff --git a/api/trace/always_off_sampler.go b/api/trace/always_off_sampler.go
index 22116f29..f0679eb6 100644
--- a/api/trace/always_off_sampler.go
+++ b/api/trace/always_off_sampler.go
@@ -15,7 +15,7 @@
 package trace
 
 import (
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 const (
@@ -36,7 +36,7 @@ func (ns alwaysOffSampler) ShouldSample(
 	_ SpanID,
 	_ string,
 	_ SpanKind,
-	_ []core.KeyValue,
+	_ []kv.KeyValue,
 	_ []Link,
 ) Decision {
 	return alwaysOffSamplerDecision
diff --git a/api/trace/always_on_sampler.go b/api/trace/always_on_sampler.go
index 05e1d805..da8d5c91 100644
--- a/api/trace/always_on_sampler.go
+++ b/api/trace/always_on_sampler.go
@@ -15,7 +15,7 @@
 package trace
 
 import (
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 const (
@@ -36,7 +36,7 @@ func (as alwaysOnSampler) ShouldSample(
 	_ SpanID,
 	_ string,
 	_ SpanKind,
-	_ []core.KeyValue,
+	_ []kv.KeyValue,
 	_ []Link,
 ) Decision {
 	return alwaysOnSamplerDecision
diff --git a/api/trace/api.go b/api/trace/api.go
index c8414d47..620e0bd2 100644
--- a/api/trace/api.go
+++ b/api/trace/api.go
@@ -20,7 +20,7 @@ import (
 
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 type Provider interface {
@@ -92,10 +92,10 @@ type Span interface {
 	End(options ...EndOption)
 
 	// AddEvent adds an event to the span.
-	AddEvent(ctx context.Context, name string, attrs ...core.KeyValue)
+	AddEvent(ctx context.Context, name string, attrs ...kv.KeyValue)
 	// AddEventWithTimestamp adds an event with a custom timestamp
 	// to the span.
-	AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...core.KeyValue)
+	AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...kv.KeyValue)
 
 	// IsRecording returns true if the span is active and recording events is enabled.
 	IsRecording() bool
@@ -120,7 +120,7 @@ type Span interface {
 	SetName(name string)
 
 	// Set span attributes
-	SetAttributes(...core.KeyValue)
+	SetAttributes(...kv.KeyValue)
 
 	// Set singular span attribute, with type inference.
 	SetAttribute(string, interface{})
@@ -132,7 +132,7 @@ type StartOption func(*StartConfig)
 // StartConfig provides options to set properties of span at the time of starting
 // a new span.
 type StartConfig struct {
-	Attributes []core.KeyValue
+	Attributes []kv.KeyValue
 	StartTime  time.Time
 	Links      []Link
 	Record     bool
@@ -153,7 +153,7 @@ type StartConfig struct {
 //      be correlated.
 type Link struct {
 	SpanContext
-	Attributes []core.KeyValue
+	Attributes []kv.KeyValue
 }
 
 // SpanKind represents the role of a Span inside a Trace. Often, this defines how a Span
@@ -221,7 +221,7 @@ func WithStartTime(t time.Time) StartOption {
 // WithAttributes sets attributes to span. These attributes provides additional
 // data about the span.
 // Multiple `WithAttributes` options appends the attributes preserving the order.
-func WithAttributes(attrs ...core.KeyValue) StartOption {
+func WithAttributes(attrs ...kv.KeyValue) StartOption {
 	return func(c *StartConfig) {
 		c.Attributes = append(c.Attributes, attrs...)
 	}
@@ -248,7 +248,7 @@ func WithNewRoot() StartOption {
 }
 
 // LinkedTo allows instantiating a Span with initial Links.
-func LinkedTo(sc SpanContext, attrs ...core.KeyValue) StartOption {
+func LinkedTo(sc SpanContext, attrs ...kv.KeyValue) StartOption {
 	return func(c *StartConfig) {
 		c.Links = append(c.Links, Link{sc, attrs})
 	}
diff --git a/api/trace/noop_span.go b/api/trace/noop_span.go
index 5d8a5134..e222ad7f 100644
--- a/api/trace/noop_span.go
+++ b/api/trace/noop_span.go
@@ -20,7 +20,7 @@ import (
 
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 type NoopSpan struct {
@@ -47,7 +47,7 @@ func (NoopSpan) SetError(v bool) {
 }
 
 // SetAttributes does nothing.
-func (NoopSpan) SetAttributes(attributes ...core.KeyValue) {
+func (NoopSpan) SetAttributes(attributes ...kv.KeyValue) {
 }
 
 // SetAttribute does nothing.
@@ -68,11 +68,11 @@ func (NoopSpan) Tracer() Tracer {
 }
 
 // AddEvent does nothing.
-func (NoopSpan) AddEvent(ctx context.Context, name string, attrs ...core.KeyValue) {
+func (NoopSpan) AddEvent(ctx context.Context, name string, attrs ...kv.KeyValue) {
 }
 
 // AddEventWithTimestamp does nothing.
-func (NoopSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...core.KeyValue) {
+func (NoopSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...kv.KeyValue) {
 }
 
 // SetName does nothing.
diff --git a/api/trace/sampler.go b/api/trace/sampler.go
index 91df24ed..b90613c7 100644
--- a/api/trace/sampler.go
+++ b/api/trace/sampler.go
@@ -14,7 +14,7 @@
 
 package trace
 
-import "go.opentelemetry.io/otel/api/core"
+import "go.opentelemetry.io/otel/api/kv"
 
 type Sampler interface {
 	// ShouldSample returns a Decision that contains a decision whether to sample
@@ -27,7 +27,7 @@ type Sampler interface {
 		spanID SpanID,
 		spanName string,
 		spanKind SpanKind,
-		attributes []core.KeyValue,
+		attributes []kv.KeyValue,
 		links []Link,
 	) Decision
 
@@ -43,5 +43,5 @@ type Decision struct {
 
 	// Attributes provides insight into Sample	r's decision process.
 	// It could be empty slice or nil if no attributes are recorded by the sampler.
-	Attributes []core.KeyValue
+	Attributes []kv.KeyValue
 }
diff --git a/bridge/opentracing/bridge.go b/bridge/opentracing/bridge.go
index 848d88f6..b4c6748b 100644
--- a/bridge/opentracing/bridge.go
+++ b/bridge/opentracing/bridge.go
@@ -27,10 +27,9 @@ import (
 	otext "github.com/opentracing/opentracing-go/ext"
 	otlog "github.com/opentracing/opentracing-go/log"
 
-	otelcore "go.opentelemetry.io/otel/api/core"
 	otelcorrelation "go.opentelemetry.io/otel/api/correlation"
 	otelglobal "go.opentelemetry.io/otel/api/global"
-	otelkey "go.opentelemetry.io/otel/api/key"
+	otelcore "go.opentelemetry.io/otel/api/kv"
 	otelpropagation "go.opentelemetry.io/otel/api/propagation"
 	oteltrace "go.opentelemetry.io/otel/api/trace"
 	otelparent "go.opentelemetry.io/otel/internal/trace/parent"
@@ -67,12 +66,12 @@ func (c *bridgeSpanContext) ForeachBaggageItem(handler func(k, v string) bool) {
 
 func (c *bridgeSpanContext) setBaggageItem(restrictedKey, value string) {
 	crk := http.CanonicalHeaderKey(restrictedKey)
-	c.baggageItems = c.baggageItems.Apply(otelcorrelation.MapUpdate{SingleKV: otelkey.New(crk).String(value)})
+	c.baggageItems = c.baggageItems.Apply(otelcorrelation.MapUpdate{SingleKV: otelcore.NewKey(crk).String(value)})
 }
 
 func (c *bridgeSpanContext) baggageItem(restrictedKey string) string {
 	crk := http.CanonicalHeaderKey(restrictedKey)
-	val, _ := c.baggageItems.Value(otelkey.New(crk))
+	val, _ := c.baggageItems.Value(otelcore.NewKey(crk))
 	return val.Emit()
 }
 
@@ -373,7 +372,7 @@ func (t *BridgeTracer) correlationGetHook(ctx context.Context, m otelcorrelation
 	}
 	kv := make([]otelcore.KeyValue, 0, len(items))
 	for k, v := range items {
-		kv = append(kv, otelkey.String(k, v))
+		kv = append(kv, otelcore.String(k, v))
 	}
 	return m.Apply(otelcorrelation.MapUpdate{MultiKV: kv})
 }
@@ -559,7 +558,7 @@ func otSpanReferenceToOtelLink(bridgeSC *bridgeSpanContext, refType ot.SpanRefer
 
 func otSpanReferenceTypeToOtelLinkAttributes(refType ot.SpanReferenceType) []otelcore.KeyValue {
 	return []otelcore.KeyValue{
-		otelkey.String("ot-span-reference-type", otSpanReferenceTypeToString(refType)),
+		otelcore.String("ot-span-reference-type", otSpanReferenceTypeToString(refType)),
 	}
 }
 
diff --git a/bridge/opentracing/internal/mock.go b/bridge/opentracing/internal/mock.go
index e3f8bd27..132b0815 100644
--- a/bridge/opentracing/internal/mock.go
+++ b/bridge/opentracing/internal/mock.go
@@ -23,9 +23,8 @@ import (
 
 	"google.golang.org/grpc/codes"
 
-	otelcore "go.opentelemetry.io/otel/api/core"
 	otelcorrelation "go.opentelemetry.io/otel/api/correlation"
-	otelkey "go.opentelemetry.io/otel/api/key"
+	otelcore "go.opentelemetry.io/otel/api/kv"
 	oteltrace "go.opentelemetry.io/otel/api/trace"
 	otelparent "go.opentelemetry.io/otel/internal/trace/parent"
 
@@ -33,12 +32,12 @@ import (
 )
 
 var (
-	ComponentKey     = otelkey.New("component")
-	ServiceKey       = otelkey.New("service")
-	StatusCodeKey    = otelkey.New("status.code")
-	StatusMessageKey = otelkey.New("status.message")
-	ErrorKey         = otelkey.New("error")
-	NameKey          = otelkey.New("name")
+	ComponentKey     = otelcore.NewKey("component")
+	ServiceKey       = otelcore.NewKey("service")
+	StatusCodeKey    = otelcore.NewKey("status.code")
+	StatusMessageKey = otelcore.NewKey("status.message")
+	ErrorKey         = otelcore.NewKey("error")
+	NameKey          = otelcore.NewKey("name")
 )
 
 type MockContextKeyValue struct {
@@ -240,7 +239,7 @@ func (s *MockSpan) SetAttributes(attributes ...otelcore.KeyValue) {
 }
 
 func (s *MockSpan) SetAttribute(k string, v interface{}) {
-	s.SetAttributes(otelkey.Infer(k, v))
+	s.SetAttributes(otelcore.Infer(k, v))
 }
 
 func (s *MockSpan) applyUpdate(update otelcorrelation.MapUpdate) {
@@ -289,8 +288,8 @@ func (s *MockSpan) RecordError(ctx context.Context, err error, opts ...oteltrace
 	}
 
 	s.AddEventWithTimestamp(ctx, cfg.Timestamp, "error",
-		otelkey.String("error.type", reflect.TypeOf(err).String()),
-		otelkey.String("error.message", err.Error()),
+		otelcore.String("error.type", reflect.TypeOf(err).String()),
+		otelcore.String("error.message", err.Error()),
 	)
 }
 
diff --git a/example/basic/main.go b/example/basic/main.go
index 625f678f..718899b7 100644
--- a/example/basic/main.go
+++ b/example/basic/main.go
@@ -18,10 +18,9 @@ import (
 	"context"
 	"log"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/correlation"
 	"go.opentelemetry.io/otel/api/global"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 	"go.opentelemetry.io/otel/api/trace"
 	metricstdout "go.opentelemetry.io/otel/exporters/metric/stdout"
@@ -31,10 +30,10 @@ import (
 )
 
 var (
-	fooKey     = key.New("ex.com/foo")
-	barKey     = key.New("ex.com/bar")
-	lemonsKey  = key.New("ex.com/lemons")
-	anotherKey = key.New("ex.com/another")
+	fooKey     = kv.NewKey("ex.com/foo")
+	barKey     = kv.NewKey("ex.com/bar")
+	lemonsKey  = kv.NewKey("ex.com/lemons")
+	anotherKey = kv.NewKey("ex.com/another")
 )
 
 // initTracer creates and registers trace provider instance.
@@ -47,7 +46,7 @@ func initTracer() {
 	}
 	tp, err := sdktrace.NewProvider(sdktrace.WithSyncer(exp),
 		sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
-		sdktrace.WithResourceAttributes(key.String("rk1", "rv11"), key.Int64("rk2", 5)))
+		sdktrace.WithResourceAttributes(kv.String("rk1", "rv11"), kv.Int64("rk2", 5)))
 	if err != nil {
 		log.Panicf("failed to initialize trace provider %v", err)
 	}
@@ -72,7 +71,7 @@ func main() {
 	tracer := global.Tracer("ex.com/basic")
 	meter := global.Meter("ex.com/basic")
 
-	commonLabels := []core.KeyValue{lemonsKey.Int(10), key.String("A", "1"), key.String("B", "2"), key.String("C", "3")}
+	commonLabels := []kv.KeyValue{lemonsKey.Int(10), kv.String("A", "1"), kv.String("B", "2"), kv.String("C", "3")}
 
 	oneMetricCB := func(result metric.Float64ObserverResult) {
 		result.Observe(1, commonLabels...)
@@ -95,7 +94,7 @@ func main() {
 
 	err := tracer.WithSpan(ctx, "operation", func(ctx context.Context) error {
 
-		trace.SpanFromContext(ctx).AddEvent(ctx, "Nice operation!", key.New("bogons").Int(100))
+		trace.SpanFromContext(ctx).AddEvent(ctx, "Nice operation!", kv.NewKey("bogons").Int(100))
 
 		trace.SpanFromContext(ctx).SetAttributes(anotherKey.String("yes"))
 
diff --git a/example/http/client/client.go b/example/http/client/client.go
index 9fc1d485..9ba7b31b 100644
--- a/example/http/client/client.go
+++ b/example/http/client/client.go
@@ -21,12 +21,13 @@ import (
 	"io/ioutil"
 	"log"
 
+	"go.opentelemetry.io/otel/api/kv"
+
 	"net/http"
 	"time"
 
 	"go.opentelemetry.io/otel/api/correlation"
 	"go.opentelemetry.io/otel/api/global"
-	"go.opentelemetry.io/otel/api/key"
 	"go.opentelemetry.io/otel/exporters/trace/stdout"
 	"go.opentelemetry.io/otel/plugin/httptrace"
 	sdktrace "go.opentelemetry.io/otel/sdk/trace"
@@ -57,7 +58,7 @@ func main() {
 
 	client := http.DefaultClient
 	ctx := correlation.NewContext(context.Background(),
-		key.String("username", "donuts"),
+		kv.String("username", "donuts"),
 	)
 
 	var body []byte
diff --git a/example/jaeger/main.go b/example/jaeger/main.go
index 24a8383c..7ef9e238 100644
--- a/example/jaeger/main.go
+++ b/example/jaeger/main.go
@@ -20,9 +20,8 @@ import (
 	"context"
 	"log"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/global"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 
 	"go.opentelemetry.io/otel/exporters/trace/jaeger"
 	sdktrace "go.opentelemetry.io/otel/sdk/trace"
@@ -35,9 +34,9 @@ func initTracer() func() {
 		jaeger.WithCollectorEndpoint("http://localhost:14268/api/traces"),
 		jaeger.WithProcess(jaeger.Process{
 			ServiceName: "trace-demo",
-			Tags: []core.KeyValue{
-				key.String("exporter", "jaeger"),
-				key.Float64("float", 312.23),
+			Tags: []kv.KeyValue{
+				kv.String("exporter", "jaeger"),
+				kv.Float64("float", 312.23),
 			},
 		}),
 		jaeger.RegisterAsGlobal(),
diff --git a/example/namedtracer/foo/foo.go b/example/namedtracer/foo/foo.go
index c6ec6af2..40e64b28 100644
--- a/example/namedtracer/foo/foo.go
+++ b/example/namedtracer/foo/foo.go
@@ -18,12 +18,12 @@ import (
 	"context"
 
 	"go.opentelemetry.io/otel/api/global"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/trace"
 )
 
 var (
-	lemonsKey = key.New("ex.com/lemons")
+	lemonsKey = kv.NewKey("ex.com/lemons")
 )
 
 // SubOperation is an example to demonstrate the use of named tracer.
diff --git a/example/namedtracer/main.go b/example/namedtracer/main.go
index 98fdabef..c3786ae3 100644
--- a/example/namedtracer/main.go
+++ b/example/namedtracer/main.go
@@ -18,9 +18,10 @@ import (
 	"context"
 	"log"
 
+	"go.opentelemetry.io/otel/api/kv"
+
 	"go.opentelemetry.io/otel/api/correlation"
 	"go.opentelemetry.io/otel/api/global"
-	"go.opentelemetry.io/otel/api/key"
 	"go.opentelemetry.io/otel/api/trace"
 	"go.opentelemetry.io/otel/example/namedtracer/foo"
 	"go.opentelemetry.io/otel/exporters/trace/stdout"
@@ -28,9 +29,9 @@ import (
 )
 
 var (
-	fooKey     = key.New("ex.com/foo")
-	barKey     = key.New("ex.com/bar")
-	anotherKey = key.New("ex.com/another")
+	fooKey     = kv.NewKey("ex.com/foo")
+	barKey     = kv.NewKey("ex.com/bar")
+	anotherKey = kv.NewKey("ex.com/another")
 )
 
 var tp *sdktrace.Provider
@@ -66,7 +67,7 @@ func main() {
 
 	err := tracer.WithSpan(ctx, "operation", func(ctx context.Context) error {
 
-		trace.SpanFromContext(ctx).AddEvent(ctx, "Nice operation!", key.New("bogons").Int(100))
+		trace.SpanFromContext(ctx).AddEvent(ctx, "Nice operation!", kv.NewKey("bogons").Int(100))
 
 		trace.SpanFromContext(ctx).SetAttributes(anotherKey.String("yes"))
 
diff --git a/example/prometheus/main.go b/example/prometheus/main.go
index 28cd42e9..6e9ba622 100644
--- a/example/prometheus/main.go
+++ b/example/prometheus/main.go
@@ -21,16 +21,15 @@ import (
 	"sync"
 	"time"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/global"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 	"go.opentelemetry.io/otel/exporters/metric/prometheus"
 	"go.opentelemetry.io/otel/sdk/metric/controller/push"
 )
 
 var (
-	lemonsKey = key.New("ex.com/lemons")
+	lemonsKey = kv.NewKey("ex.com/lemons")
 )
 
 func initMeter() *push.Controller {
@@ -52,7 +51,7 @@ func main() {
 	meter := global.Meter("ex.com/basic")
 	observerLock := new(sync.RWMutex)
 	observerValueToReport := new(float64)
-	observerLabelsToReport := new([]core.KeyValue)
+	observerLabelsToReport := new([]kv.KeyValue)
 	cb := func(result metric.Float64ObserverResult) {
 		(*observerLock).RLock()
 		value := *observerValueToReport
@@ -67,8 +66,8 @@ func main() {
 	measureTwo := metric.Must(meter).NewFloat64Measure("ex.com.two")
 	measureThree := metric.Must(meter).NewFloat64Counter("ex.com.three")
 
-	commonLabels := []core.KeyValue{lemonsKey.Int(10), key.String("A", "1"), key.String("B", "2"), key.String("C", "3")}
-	notSoCommonLabels := []core.KeyValue{lemonsKey.Int(13)}
+	commonLabels := []kv.KeyValue{lemonsKey.Int(10), kv.String("A", "1"), kv.String("B", "2"), kv.String("C", "3")}
+	notSoCommonLabels := []kv.KeyValue{lemonsKey.Int(13)}
 
 	ctx := context.Background()
 
diff --git a/exporters/otlp/internal/transform/attribute.go b/exporters/otlp/internal/transform/attribute.go
index 9b8fe996..b3ca6087 100644
--- a/exporters/otlp/internal/transform/attribute.go
+++ b/exporters/otlp/internal/transform/attribute.go
@@ -17,12 +17,14 @@ package transform
 import (
 	commonpb "github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv/value"
+
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/sdk/resource"
 )
 
 // Attributes transforms a slice of KeyValues into a slice of OTLP attribute key-values.
-func Attributes(attrs []core.KeyValue) []*commonpb.AttributeKeyValue {
+func Attributes(attrs []kv.KeyValue) []*commonpb.AttributeKeyValue {
 	if len(attrs) == 0 {
 		return nil
 	}
@@ -48,33 +50,33 @@ func ResourceAttributes(resource *resource.Resource) []*commonpb.AttributeKeyVal
 	return out
 }
 
-func toAttribute(v core.KeyValue) *commonpb.AttributeKeyValue {
+func toAttribute(v kv.KeyValue) *commonpb.AttributeKeyValue {
 	switch v.Value.Type() {
-	case core.BOOL:
+	case value.BOOL:
 		return &commonpb.AttributeKeyValue{
 			Key:       string(v.Key),
 			Type:      commonpb.AttributeKeyValue_BOOL,
 			BoolValue: v.Value.AsBool(),
 		}
-	case core.INT64, core.INT32, core.UINT32, core.UINT64:
+	case value.INT64, value.INT32, value.UINT32, value.UINT64:
 		return &commonpb.AttributeKeyValue{
 			Key:      string(v.Key),
 			Type:     commonpb.AttributeKeyValue_INT,
 			IntValue: v.Value.AsInt64(),
 		}
-	case core.FLOAT32:
+	case value.FLOAT32:
 		return &commonpb.AttributeKeyValue{
 			Key:         string(v.Key),
 			Type:        commonpb.AttributeKeyValue_DOUBLE,
 			DoubleValue: float64(v.Value.AsFloat32()),
 		}
-	case core.FLOAT64:
+	case value.FLOAT64:
 		return &commonpb.AttributeKeyValue{
 			Key:         string(v.Key),
 			Type:        commonpb.AttributeKeyValue_DOUBLE,
 			DoubleValue: v.Value.AsFloat64(),
 		}
-	case core.STRING:
+	case value.STRING:
 		return &commonpb.AttributeKeyValue{
 			Key:         string(v.Key),
 			Type:        commonpb.AttributeKeyValue_STRING,
diff --git a/exporters/trace/jaeger/jaeger.go b/exporters/trace/jaeger/jaeger.go
index 1e809252..1ebcaf70 100644
--- a/exporters/trace/jaeger/jaeger.go
+++ b/exporters/trace/jaeger/jaeger.go
@@ -19,11 +19,13 @@ import (
 	"encoding/binary"
 	"log"
 
+	"go.opentelemetry.io/otel/api/kv/value"
+
 	"google.golang.org/api/support/bundler"
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/global"
+	"go.opentelemetry.io/otel/api/kv"
 	gen "go.opentelemetry.io/otel/exporters/trace/jaeger/internal/gen-go/jaeger"
 	export "go.opentelemetry.io/otel/sdk/export/trace"
 	sdktrace "go.opentelemetry.io/otel/sdk/trace"
@@ -176,7 +178,7 @@ type Process struct {
 	ServiceName string
 
 	// Tags are added to Jaeger Process exports
-	Tags []core.KeyValue
+	Tags []kv.KeyValue
 }
 
 // Exporter is an implementation of trace.SpanSyncer that uploads spans to Jaeger.
@@ -271,48 +273,48 @@ func spanDataToThrift(data *export.SpanData) *gen.Span {
 	}
 }
 
-func keyValueToTag(kv core.KeyValue) *gen.Tag {
+func keyValueToTag(keyValue kv.KeyValue) *gen.Tag {
 	var tag *gen.Tag
-	switch kv.Value.Type() {
-	case core.STRING:
-		s := kv.Value.AsString()
+	switch keyValue.Value.Type() {
+	case value.STRING:
+		s := keyValue.Value.AsString()
 		tag = &gen.Tag{
-			Key:   string(kv.Key),
+			Key:   string(keyValue.Key),
 			VStr:  &s,
 			VType: gen.TagType_STRING,
 		}
-	case core.BOOL:
-		b := kv.Value.AsBool()
+	case value.BOOL:
+		b := keyValue.Value.AsBool()
 		tag = &gen.Tag{
-			Key:   string(kv.Key),
+			Key:   string(keyValue.Key),
 			VBool: &b,
 			VType: gen.TagType_BOOL,
 		}
-	case core.INT32:
-		i := int64(kv.Value.AsInt32())
+	case value.INT32:
+		i := int64(keyValue.Value.AsInt32())
 		tag = &gen.Tag{
-			Key:   string(kv.Key),
+			Key:   string(keyValue.Key),
 			VLong: &i,
 			VType: gen.TagType_LONG,
 		}
-	case core.INT64:
-		i := kv.Value.AsInt64()
+	case value.INT64:
+		i := keyValue.Value.AsInt64()
 		tag = &gen.Tag{
-			Key:   string(kv.Key),
+			Key:   string(keyValue.Key),
 			VLong: &i,
 			VType: gen.TagType_LONG,
 		}
-	case core.FLOAT32:
-		f := float64(kv.Value.AsFloat32())
+	case value.FLOAT32:
+		f := float64(keyValue.Value.AsFloat32())
 		tag = &gen.Tag{
-			Key:     string(kv.Key),
+			Key:     string(keyValue.Key),
 			VDouble: &f,
 			VType:   gen.TagType_DOUBLE,
 		}
-	case core.FLOAT64:
-		f := kv.Value.AsFloat64()
+	case value.FLOAT64:
+		f := keyValue.Value.AsFloat64()
 		tag = &gen.Tag{
-			Key:     string(kv.Key),
+			Key:     string(keyValue.Key),
 			VDouble: &f,
 			VType:   gen.TagType_DOUBLE,
 		}
diff --git a/exporters/trace/zipkin/model.go b/exporters/trace/zipkin/model.go
index 4c2efb3c..a320d33d 100644
--- a/exporters/trace/zipkin/model.go
+++ b/exporters/trace/zipkin/model.go
@@ -21,7 +21,7 @@ import (
 
 	zkmodel "github.com/openzipkin/zipkin-go/model"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/trace"
 	export "go.opentelemetry.io/otel/sdk/export/trace"
 )
@@ -122,7 +122,7 @@ func toZipkinAnnotations(events []export.Event) []zkmodel.Annotation {
 	return annotations
 }
 
-func attributesToJSONMapString(attributes []core.KeyValue) string {
+func attributesToJSONMapString(attributes []kv.KeyValue) string {
 	m := make(map[string]interface{}, len(attributes))
 	for _, attribute := range attributes {
 		m[(string)(attribute.Key)] = attribute.Value.AsInterface()
diff --git a/internal/metric/mock.go b/internal/metric/mock.go
index 86ca382f..9a50410a 100644
--- a/internal/metric/mock.go
+++ b/internal/metric/mock.go
@@ -18,7 +18,7 @@ import (
 	"context"
 	"sync"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 	apimetric "go.opentelemetry.io/otel/api/metric"
 	"go.opentelemetry.io/otel/api/metric/registry"
@@ -27,14 +27,14 @@ import (
 type (
 	Handle struct {
 		Instrument *Sync
-		Labels     []core.KeyValue
+		Labels     []kv.KeyValue
 	}
 
 	Batch struct {
 		// Measurement needs to be aligned for 64-bit atomic operations.
 		Measurements []Measurement
 		Ctx          context.Context
-		Labels       []core.KeyValue
+		Labels       []kv.KeyValue
 		LibraryName  string
 	}
 
@@ -64,7 +64,7 @@ type (
 	Async struct {
 		Instrument
 
-		callback func(func(apimetric.Number, []core.KeyValue))
+		callback func(func(apimetric.Number, []kv.KeyValue))
 	}
 
 	Sync struct {
@@ -91,14 +91,14 @@ func (s *Sync) Implementation() interface{} {
 	return s
 }
 
-func (s *Sync) Bind(labels []core.KeyValue) apimetric.BoundSyncImpl {
+func (s *Sync) Bind(labels []kv.KeyValue) apimetric.BoundSyncImpl {
 	return &Handle{
 		Instrument: s,
 		Labels:     labels,
 	}
 }
 
-func (s *Sync) RecordOne(ctx context.Context, number apimetric.Number, labels []core.KeyValue) {
+func (s *Sync) RecordOne(ctx context.Context, number apimetric.Number, labels []kv.KeyValue) {
 	s.meter.doRecordSingle(ctx, labels, s, number)
 }
 
@@ -109,7 +109,7 @@ func (h *Handle) RecordOne(ctx context.Context, number apimetric.Number) {
 func (h *Handle) Unbind() {
 }
 
-func (m *MeterImpl) doRecordSingle(ctx context.Context, labels []core.KeyValue, instrument apimetric.InstrumentImpl, number apimetric.Number) {
+func (m *MeterImpl) doRecordSingle(ctx context.Context, labels []kv.KeyValue, instrument apimetric.InstrumentImpl, number apimetric.Number) {
 	m.recordMockBatch(ctx, labels, Measurement{
 		Instrument: instrument,
 		Number:     number,
@@ -152,7 +152,7 @@ func (m *MeterImpl) NewSyncInstrument(descriptor metric.Descriptor) (apimetric.S
 	}, nil
 }
 
-func (m *MeterImpl) NewAsyncInstrument(descriptor metric.Descriptor, callback func(func(apimetric.Number, []core.KeyValue))) (apimetric.AsyncImpl, error) {
+func (m *MeterImpl) NewAsyncInstrument(descriptor metric.Descriptor, callback func(func(apimetric.Number, []kv.KeyValue))) (apimetric.AsyncImpl, error) {
 	a := &Async{
 		Instrument: Instrument{
 			descriptor: descriptor,
@@ -164,7 +164,7 @@ func (m *MeterImpl) NewAsyncInstrument(descriptor metric.Descriptor, callback fu
 	return a, nil
 }
 
-func (m *MeterImpl) RecordBatch(ctx context.Context, labels []core.KeyValue, measurements ...apimetric.Measurement) {
+func (m *MeterImpl) RecordBatch(ctx context.Context, labels []kv.KeyValue, measurements ...apimetric.Measurement) {
 	mm := make([]Measurement, len(measurements))
 	for i := 0; i < len(measurements); i++ {
 		m := measurements[i]
@@ -176,7 +176,7 @@ func (m *MeterImpl) RecordBatch(ctx context.Context, labels []core.KeyValue, mea
 	m.recordMockBatch(ctx, labels, mm...)
 }
 
-func (m *MeterImpl) recordMockBatch(ctx context.Context, labels []core.KeyValue, measurements ...Measurement) {
+func (m *MeterImpl) recordMockBatch(ctx context.Context, labels []kv.KeyValue, measurements ...Measurement) {
 	m.MeasurementBatches = append(m.MeasurementBatches, Batch{
 		Ctx:          ctx,
 		Labels:       labels,
@@ -186,7 +186,7 @@ func (m *MeterImpl) recordMockBatch(ctx context.Context, labels []core.KeyValue,
 
 func (m *MeterImpl) RunAsyncInstruments() {
 	for _, observer := range m.AsyncInstruments {
-		observer.callback(func(n apimetric.Number, labels []core.KeyValue) {
+		observer.callback(func(n apimetric.Number, labels []kv.KeyValue) {
 			m.doRecordSingle(context.Background(), labels, observer, n)
 		})
 	}
diff --git a/internal/trace/mock_span.go b/internal/trace/mock_span.go
index f8f59459..a86653fe 100644
--- a/internal/trace/mock_span.go
+++ b/internal/trace/mock_span.go
@@ -20,7 +20,7 @@ import (
 
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	apitrace "go.opentelemetry.io/otel/api/trace"
 )
 
@@ -33,8 +33,8 @@ type MockSpan struct {
 
 var _ apitrace.Span = (*MockSpan)(nil)
 
-// SpanContext returns associated core.SpanContext. If the receiver is nil it returns
-// an empty core.SpanContext
+// SpanContext returns associated kv.SpanContext. If the receiver is nil it returns
+// an empty kv.SpanContext
 func (ms *MockSpan) SpanContext() apitrace.SpanContext {
 	if ms == nil {
 		return apitrace.EmptySpanContext()
@@ -56,7 +56,7 @@ func (ms *MockSpan) SetError(v bool) {
 }
 
 // SetAttributes does nothing.
-func (ms *MockSpan) SetAttributes(attributes ...core.KeyValue) {
+func (ms *MockSpan) SetAttributes(attributes ...kv.KeyValue) {
 }
 
 // SetAttribute does nothing.
@@ -82,9 +82,9 @@ func (ms *MockSpan) Tracer() apitrace.Tracer {
 }
 
 // AddEvent does nothing.
-func (ms *MockSpan) AddEvent(ctx context.Context, name string, attrs ...core.KeyValue) {
+func (ms *MockSpan) AddEvent(ctx context.Context, name string, attrs ...kv.KeyValue) {
 }
 
 // AddEvent does nothing.
-func (ms *MockSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...core.KeyValue) {
+func (ms *MockSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...kv.KeyValue) {
 }
diff --git a/internal/trace/parent/parent.go b/internal/trace/parent/parent.go
index 7aac9508..5080aed9 100644
--- a/internal/trace/parent/parent.go
+++ b/internal/trace/parent/parent.go
@@ -17,8 +17,7 @@ package parent
 import (
 	"context"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/trace"
 )
 
@@ -47,8 +46,8 @@ func addLinkIfValid(links []trace.Link, sc trace.SpanContext, kind string) []tra
 	}
 	return append(links, trace.Link{
 		SpanContext: sc,
-		Attributes: []core.KeyValue{
-			key.String("ignored-on-demand", kind),
+		Attributes: []kv.KeyValue{
+			kv.String("ignored-on-demand", kind),
 		},
 	})
 }
diff --git a/plugin/grpctrace/grpctrace.go b/plugin/grpctrace/grpctrace.go
index 9e27b2a9..294cc0db 100644
--- a/plugin/grpctrace/grpctrace.go
+++ b/plugin/grpctrace/grpctrace.go
@@ -19,9 +19,9 @@ import (
 
 	"google.golang.org/grpc/metadata"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/correlation"
 	"go.opentelemetry.io/otel/api/global"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/propagation"
 	"go.opentelemetry.io/otel/api/trace"
 )
@@ -54,14 +54,14 @@ func Inject(ctx context.Context, metadata *metadata.MD) {
 // Extract returns the correlation context and span context that
 // another service encoded in the gRPC metadata object with Inject.
 // This function is meant to be used on incoming requests.
-func Extract(ctx context.Context, metadata *metadata.MD) ([]core.KeyValue, trace.SpanContext) {
+func Extract(ctx context.Context, metadata *metadata.MD) ([]kv.KeyValue, trace.SpanContext) {
 	ctx = propagation.ExtractHTTP(ctx, global.Propagators(), &metadataSupplier{
 		metadata: metadata,
 	})
 
 	spanContext := trace.RemoteSpanContextFromContext(ctx)
-	var correlationCtxKVs []core.KeyValue
-	correlation.MapFromContext(ctx).Foreach(func(kv core.KeyValue) bool {
+	var correlationCtxKVs []kv.KeyValue
+	correlation.MapFromContext(ctx).Foreach(func(kv kv.KeyValue) bool {
 		correlationCtxKVs = append(correlationCtxKVs, kv)
 		return true
 	})
diff --git a/plugin/grpctrace/interceptor.go b/plugin/grpctrace/interceptor.go
index f3f13963..9dbdcf13 100644
--- a/plugin/grpctrace/interceptor.go
+++ b/plugin/grpctrace/interceptor.go
@@ -28,20 +28,19 @@ import (
 	"google.golang.org/grpc/peer"
 	"google.golang.org/grpc/status"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/correlation"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/trace"
 )
 
 var (
-	rpcServiceKey  = key.New("rpc.service")
-	netPeerIPKey   = key.New("net.peer.ip")
-	netPeerPortKey = key.New("net.peer.port")
+	rpcServiceKey  = kv.NewKey("rpc.service")
+	netPeerIPKey   = kv.NewKey("net.peer.ip")
+	netPeerPortKey = kv.NewKey("net.peer.port")
 
-	messageTypeKey             = key.New("message.type")
-	messageIDKey               = key.New("message.id")
-	messageUncompressedSizeKey = key.New("message.uncompressed_size")
+	messageTypeKey             = kv.NewKey("message.type")
+	messageIDKey               = kv.NewKey("message.id")
+	messageUncompressedSizeKey = kv.NewKey("message.uncompressed_size")
 )
 
 const (
@@ -399,28 +398,28 @@ func StreamServerInterceptor(tracer trace.Tracer) grpc.StreamServerInterceptor {
 	}
 }
 
-func peerInfoFromTarget(target string) []core.KeyValue {
+func peerInfoFromTarget(target string) []kv.KeyValue {
 	host, port, err := net.SplitHostPort(target)
 
 	if err != nil {
-		return []core.KeyValue{}
+		return []kv.KeyValue{}
 	}
 
 	if host == "" {
 		host = "127.0.0.1"
 	}
 
-	return []core.KeyValue{
+	return []kv.KeyValue{
 		netPeerIPKey.String(host),
 		netPeerPortKey.String(port),
 	}
 }
 
-func peerInfoFromContext(ctx context.Context) []core.KeyValue {
+func peerInfoFromContext(ctx context.Context) []kv.KeyValue {
 	p, ok := peer.FromContext(ctx)
 
 	if !ok {
-		return []core.KeyValue{}
+		return []kv.KeyValue{}
 	}
 
 	return peerInfoFromTarget(p.Addr.String())
diff --git a/plugin/httptrace/clienttrace.go b/plugin/httptrace/clienttrace.go
index f7e86402..2f485195 100644
--- a/plugin/httptrace/clienttrace.go
+++ b/plugin/httptrace/clienttrace.go
@@ -24,17 +24,16 @@ import (
 
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/global"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/trace"
 )
 
 var (
-	HTTPStatus     = key.New("http.status")
-	HTTPHeaderMIME = key.New("http.mime")
-	HTTPRemoteAddr = key.New("http.remote")
-	HTTPLocalAddr  = key.New("http.local")
+	HTTPStatus     = kv.NewKey("http.status")
+	HTTPHeaderMIME = kv.NewKey("http.mime")
+	HTTPRemoteAddr = kv.NewKey("http.remote")
+	HTTPLocalAddr  = kv.NewKey("http.local")
 )
 
 var (
@@ -90,7 +89,7 @@ func NewClientTrace(ctx context.Context) *httptrace.ClientTrace {
 	}
 }
 
-func (ct *clientTracer) start(hook, spanName string, attrs ...core.KeyValue) {
+func (ct *clientTracer) start(hook, spanName string, attrs ...kv.KeyValue) {
 	ct.mtx.Lock()
 	defer ct.mtx.Unlock()
 
@@ -110,7 +109,7 @@ func (ct *clientTracer) start(hook, spanName string, attrs ...core.KeyValue) {
 	}
 }
 
-func (ct *clientTracer) end(hook string, err error, attrs ...core.KeyValue) {
+func (ct *clientTracer) end(hook string, err error, attrs ...kv.KeyValue) {
 	ct.mtx.Lock()
 	defer ct.mtx.Unlock()
 	if ctx, ok := ct.activeHooks[hook]; ok {
@@ -198,7 +197,7 @@ func (ct *clientTracer) wroteHeaderField(k string, v []string) {
 	if ct.span("http.headers") == nil {
 		ct.start("http.headers", "http.headers")
 	}
-	ct.root.SetAttributes(key.String("http."+strings.ToLower(k), sliceToString(v)))
+	ct.root.SetAttributes(kv.String("http."+strings.ToLower(k), sliceToString(v)))
 }
 
 func (ct *clientTracer) wroteHeaders() {
diff --git a/plugin/httptrace/httptrace.go b/plugin/httptrace/httptrace.go
index 70394027..2955a301 100644
--- a/plugin/httptrace/httptrace.go
+++ b/plugin/httptrace/httptrace.go
@@ -18,30 +18,29 @@ import (
 	"context"
 	"net/http"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/correlation"
 	"go.opentelemetry.io/otel/api/global"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/propagation"
 	"go.opentelemetry.io/otel/api/trace"
 )
 
 var (
-	HostKey = key.New("http.host")
-	URLKey  = key.New("http.url")
+	HostKey = kv.NewKey("http.host")
+	URLKey  = kv.NewKey("http.url")
 )
 
 // Returns the Attributes, Context Entries, and SpanContext that were encoded by Inject.
-func Extract(ctx context.Context, req *http.Request) ([]core.KeyValue, []core.KeyValue, trace.SpanContext) {
+func Extract(ctx context.Context, req *http.Request) ([]kv.KeyValue, []kv.KeyValue, trace.SpanContext) {
 	ctx = propagation.ExtractHTTP(ctx, global.Propagators(), req.Header)
 
-	attrs := []core.KeyValue{
+	attrs := []kv.KeyValue{
 		URLKey.String(req.URL.String()),
 		// Etc.
 	}
 
-	var correlationCtxKVs []core.KeyValue
-	correlation.MapFromContext(ctx).Foreach(func(kv core.KeyValue) bool {
+	var correlationCtxKVs []kv.KeyValue
+	correlation.MapFromContext(ctx).Foreach(func(kv kv.KeyValue) bool {
 		correlationCtxKVs = append(correlationCtxKVs, kv)
 		return true
 	})
diff --git a/plugin/othttp/common.go b/plugin/othttp/common.go
index 2f08e51f..ff48ac85 100644
--- a/plugin/othttp/common.go
+++ b/plugin/othttp/common.go
@@ -17,24 +17,25 @@ package othttp
 import (
 	"net/http"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
+
 	"go.opentelemetry.io/otel/api/trace"
 )
 
 // Attribute keys that can be added to a span.
 const (
-	HostKey       = core.Key("http.host")        // the HTTP host (http.Request.Host)
-	MethodKey     = core.Key("http.method")      // the HTTP method (http.Request.Method)
-	PathKey       = core.Key("http.path")        // the HTTP path (http.Request.URL.Path)
-	URLKey        = core.Key("http.url")         // the HTTP URL (http.Request.URL.String())
-	UserAgentKey  = core.Key("http.user_agent")  // the HTTP user agent (http.Request.UserAgent())
-	RouteKey      = core.Key("http.route")       // the HTTP route (ex: /users/:id)
-	RemoteAddrKey = core.Key("http.remote_addr") // the network address of the client that sent the HTTP request (http.Request.RemoteAddr)
-	StatusCodeKey = core.Key("http.status_code") // if set, the HTTP status
-	ReadBytesKey  = core.Key("http.read_bytes")  // if anything was read from the request body, the total number of bytes read
-	ReadErrorKey  = core.Key("http.read_error")  // If an error occurred while reading a request, the string of the error (io.EOF is not recorded)
-	WroteBytesKey = core.Key("http.wrote_bytes") // if anything was written to the response writer, the total number of bytes written
-	WriteErrorKey = core.Key("http.write_error") // if an error occurred while writing a reply, the string of the error (io.EOF is not recorded)
+	HostKey       = kv.Key("http.host")        // the HTTP host (http.Request.Host)
+	MethodKey     = kv.Key("http.method")      // the HTTP method (http.Request.Method)
+	PathKey       = kv.Key("http.path")        // the HTTP path (http.Request.URL.Path)
+	URLKey        = kv.Key("http.url")         // the HTTP URL (http.Request.URL.String())
+	UserAgentKey  = kv.Key("http.user_agent")  // the HTTP user agent (http.Request.UserAgent())
+	RouteKey      = kv.Key("http.route")       // the HTTP route (ex: /users/:id)
+	RemoteAddrKey = kv.Key("http.remote_addr") // the network address of the client that sent the HTTP request (http.Request.RemoteAddr)
+	StatusCodeKey = kv.Key("http.status_code") // if set, the HTTP status
+	ReadBytesKey  = kv.Key("http.read_bytes")  // if anything was read from the request body, the total number of bytes read
+	ReadErrorKey  = kv.Key("http.read_error")  // If an error occurred while reading a request, the string of the error (io.EOF is not recorded)
+	WroteBytesKey = kv.Key("http.wrote_bytes") // if anything was written to the response writer, the total number of bytes written
+	WriteErrorKey = kv.Key("http.write_error") // if an error occurred while writing a reply, the string of the error (io.EOF is not recorded)
 )
 
 // Filter is a predicate used to determine whether a given http.request should
diff --git a/plugin/othttp/handler.go b/plugin/othttp/handler.go
index d620dec1..c75c8d1f 100644
--- a/plugin/othttp/handler.go
+++ b/plugin/othttp/handler.go
@@ -18,8 +18,8 @@ import (
 	"io"
 	"net/http"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/global"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/propagation"
 	"go.opentelemetry.io/otel/api/trace"
 )
@@ -29,7 +29,7 @@ var _ http.Handler = &Handler{}
 // Handler is http middleware that corresponds to the http.Handler interface and
 // is designed to wrap a http.Mux (or equivalent), while individual routes on
 // the mux are wrapped with WithRouteTag. A Handler will add various attributes
-// to the span using the core.Keys defined in this package.
+// to the span using the kv.Keys defined in this package.
 type Handler struct {
 	operation string
 	handler   http.Handler
@@ -121,7 +121,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 }
 
 func setAfterServeAttributes(span trace.Span, read, wrote, statusCode int64, rerr, werr error) {
-	kv := make([]core.KeyValue, 0, 5)
+	kv := make([]kv.KeyValue, 0, 5)
 	// TODO: Consider adding an event after each read and write, possibly as an
 	// option (defaulting to off), so as to not create needlessly verbose spans.
 	if read > 0 {
diff --git a/sdk/export/trace/trace.go b/sdk/export/trace/trace.go
index f76067cf..b608c532 100644
--- a/sdk/export/trace/trace.go
+++ b/sdk/export/trace/trace.go
@@ -20,7 +20,7 @@ import (
 
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	apitrace "go.opentelemetry.io/otel/api/trace"
 	"go.opentelemetry.io/otel/sdk/resource"
 )
@@ -56,7 +56,7 @@ type SpanData struct {
 	// The wall clock time of EndTime will be adjusted to always be offset
 	// from StartTime by the duration of the span.
 	EndTime                  time.Time
-	Attributes               []core.KeyValue
+	Attributes               []kv.KeyValue
 	MessageEvents            []Event
 	Links                    []apitrace.Link
 	StatusCode               codes.Code
@@ -79,8 +79,8 @@ type Event struct {
 	// Name is the name of this event
 	Name string
 
-	// Attributes contains a list of keyvalue pairs.
-	Attributes []core.KeyValue
+	// Attributes contains a list of kv pairs.
+	Attributes []kv.KeyValue
 
 	// Time is the time at which this event was recorded.
 	Time time.Time
diff --git a/sdk/metric/aggregator/histogram/histogram.go b/sdk/metric/aggregator/histogram/histogram.go
index f584272d..f861d965 100644
--- a/sdk/metric/aggregator/histogram/histogram.go
+++ b/sdk/metric/aggregator/histogram/histogram.go
@@ -162,7 +162,7 @@ func (c *Aggregator) Merge(oa export.Aggregator, desc *metric.Descriptor) error
 	return nil
 }
 
-// numbers is an auxiliary struct to order histogram bucket boundaries (slice of core.Number)
+// numbers is an auxiliary struct to order histogram bucket boundaries (slice of kv.Number)
 type numbers struct {
 	numbers []metric.Number
 	kind    metric.NumberKind
diff --git a/sdk/metric/doc.go b/sdk/metric/doc.go
index 269077e4..cee67d00 100644
--- a/sdk/metric/doc.go
+++ b/sdk/metric/doc.go
@@ -28,7 +28,7 @@ boilerplate.  The API and SDK are separated such that an event reaching
 the SDK has a uniform structure: an instrument, a label set, and a
 numerical value.
 
-To this end, the API uses a core.Number type to represent either an int64
+To this end, the API uses a kv.Number type to represent either an int64
 or a float64, depending on the instrument's definition.  A single
 implementation interface is used for counter and measure instruments,
 metric.InstrumentImpl, and a single implementation interface is used for
diff --git a/sdk/metric/sdk.go b/sdk/metric/sdk.go
index 7d5cd436..48734599 100644
--- a/sdk/metric/sdk.go
+++ b/sdk/metric/sdk.go
@@ -22,7 +22,7 @@ import (
 	"sync"
 	"sync/atomic"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/label"
 	"go.opentelemetry.io/otel/api/metric"
 	api "go.opentelemetry.io/otel/api/metric"
@@ -130,7 +130,7 @@ type (
 		// labelset and recorder
 		recorders map[label.Distinct]*labeledRecorder
 
-		callback func(func(api.Number, []core.KeyValue))
+		callback func(func(api.Number, []kv.KeyValue))
 	}
 
 	labeledRecorder struct {
@@ -161,7 +161,7 @@ func (s *syncInstrument) Implementation() interface{} {
 	return s
 }
 
-func (a *asyncInstrument) observe(number api.Number, labels []core.KeyValue) {
+func (a *asyncInstrument) observe(number api.Number, labels []kv.KeyValue) {
 	if err := aggregator.RangeTest(number, &a.descriptor); err != nil {
 		a.meter.errorHandler(err)
 		return
@@ -178,7 +178,7 @@ func (a *asyncInstrument) observe(number api.Number, labels []core.KeyValue) {
 	}
 }
 
-func (a *asyncInstrument) getRecorder(kvs []core.KeyValue) export.Aggregator {
+func (a *asyncInstrument) getRecorder(kvs []kv.KeyValue) export.Aggregator {
 	// We are in a single-threaded context.  Note: this assumption
 	// could be violated if the user added concurrency within
 	// their callback.
@@ -220,7 +220,7 @@ func (m *Accumulator) SetErrorHandler(f ErrorHandler) {
 // support re-use of the orderedLabels computed by a previous
 // measurement in the same batch.   This performs two allocations
 // in the common case.
-func (s *syncInstrument) acquireHandle(kvs []core.KeyValue, labelPtr *label.Set) *record {
+func (s *syncInstrument) acquireHandle(kvs []kv.KeyValue, labelPtr *label.Set) *record {
 	var rec *record
 	var equiv label.Distinct
 
@@ -292,11 +292,11 @@ func (s *syncInstrument) acquireHandle(kvs []core.KeyValue, labelPtr *label.Set)
 	}
 }
 
-func (s *syncInstrument) Bind(kvs []core.KeyValue) api.BoundSyncImpl {
+func (s *syncInstrument) Bind(kvs []kv.KeyValue) api.BoundSyncImpl {
 	return s.acquireHandle(kvs, nil)
 }
 
-func (s *syncInstrument) RecordOne(ctx context.Context, number api.Number, kvs []core.KeyValue) {
+func (s *syncInstrument) RecordOne(ctx context.Context, number api.Number, kvs []kv.KeyValue) {
 	h := s.acquireHandle(kvs, nil)
 	defer h.Unbind()
 	h.RecordOne(ctx, number)
@@ -336,7 +336,7 @@ func (m *Accumulator) NewSyncInstrument(descriptor api.Descriptor) (api.SyncImpl
 	}, nil
 }
 
-func (m *Accumulator) NewAsyncInstrument(descriptor api.Descriptor, callback func(func(api.Number, []core.KeyValue))) (api.AsyncImpl, error) {
+func (m *Accumulator) NewAsyncInstrument(descriptor api.Descriptor, callback func(func(api.Number, []kv.KeyValue))) (api.AsyncImpl, error) {
 	a := &asyncInstrument{
 		instrument: instrument{
 			descriptor: descriptor,
@@ -464,7 +464,7 @@ func (m *Accumulator) checkpoint(ctx context.Context, descriptor *metric.Descrip
 }
 
 // RecordBatch enters a batch of metric events.
-func (m *Accumulator) RecordBatch(ctx context.Context, kvs []core.KeyValue, measurements ...api.Measurement) {
+func (m *Accumulator) RecordBatch(ctx context.Context, kvs []kv.KeyValue, measurements ...api.Measurement) {
 	// Labels will be computed the first time acquireHandle is
 	// called.  Subsequent calls to acquireHandle will re-use the
 	// previously computed value instead of recomputing the
diff --git a/sdk/resource/resource.go b/sdk/resource/resource.go
index c6c71f26..4f107e03 100644
--- a/sdk/resource/resource.go
+++ b/sdk/resource/resource.go
@@ -17,7 +17,7 @@
 package resource
 
 import (
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/label"
 )
 
@@ -34,10 +34,10 @@ type Resource struct {
 
 var emptyResource Resource
 
-// New creates a resource from a set of attributes.  If there are
+// NewKey creates a resource from a set of attributes.  If there are
 // duplicate keys present in the list of attributes, then the last
 // value found for the key is preserved.
-func New(kvs ...core.KeyValue) *Resource {
+func New(kvs ...kv.KeyValue) *Resource {
 	return &Resource{
 		labels: label.NewSet(kvs...),
 	}
@@ -57,7 +57,7 @@ func (r *Resource) String() string {
 
 // Attributes returns a copy of attributes from the resource in a sorted order.
 // To avoid allocating a new slice, use an iterator.
-func (r *Resource) Attributes() []core.KeyValue {
+func (r *Resource) Attributes() []kv.KeyValue {
 	if r == nil {
 		r = Empty()
 	}
@@ -96,7 +96,7 @@ func Merge(a, b *Resource) *Resource {
 		b = Empty()
 	}
 	// Note: 'b' is listed first so that 'a' will overwrite with
-	// last-value-wins in label.New()
+	// last-value-wins in label.NewKey()
 	combine := append(b.Attributes(), a.Attributes()...)
 	return New(combine...)
 }
diff --git a/sdk/trace/attributesMap.go b/sdk/trace/attributesMap.go
index 9eea73f1..aa938d1b 100644
--- a/sdk/trace/attributesMap.go
+++ b/sdk/trace/attributesMap.go
@@ -17,7 +17,7 @@ package trace
 import (
 	"container/list"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/sdk/export/trace"
 )
 
@@ -26,9 +26,9 @@ import (
 // Updates are allowed and refreshes the usage of the key.
 //
 // This is based from https://github.com/hashicorp/golang-lru/blob/master/simplelru/lru.go
-// With a subset of the its operations and specific for holding core.KeyValue
+// With a subset of the its operations and specific for holding kv.KeyValue
 type attributesMap struct {
-	attributes   map[core.Key]*list.Element
+	attributes   map[kv.Key]*list.Element
 	evictList    *list.List
 	droppedCount int
 	capacity     int
@@ -36,14 +36,14 @@ type attributesMap struct {
 
 func newAttributesMap(capacity int) *attributesMap {
 	lm := &attributesMap{
-		attributes: make(map[core.Key]*list.Element),
+		attributes: make(map[kv.Key]*list.Element),
 		evictList:  list.New(),
 		capacity:   capacity,
 	}
 	return lm
 }
 
-func (am *attributesMap) add(kv core.KeyValue) {
+func (am *attributesMap) add(kv kv.KeyValue) {
 	// Check for existing item
 	if ent, ok := am.attributes[kv.Key]; ok {
 		am.evictList.MoveToFront(ent)
@@ -68,9 +68,9 @@ func (am *attributesMap) toSpanData(sd *trace.SpanData) {
 		return
 	}
 
-	attributes := make([]core.KeyValue, 0, len)
+	attributes := make([]kv.KeyValue, 0, len)
 	for ent := am.evictList.Back(); ent != nil; ent = ent.Prev() {
-		if value, ok := ent.Value.(*core.KeyValue); ok {
+		if value, ok := ent.Value.(*kv.KeyValue); ok {
 			attributes = append(attributes, *value)
 		}
 	}
@@ -84,7 +84,7 @@ func (am *attributesMap) removeOldest() {
 	ent := am.evictList.Back()
 	if ent != nil {
 		am.evictList.Remove(ent)
-		kv := ent.Value.(*core.KeyValue)
+		kv := ent.Value.(*kv.KeyValue)
 		delete(am.attributes, kv.Key)
 	}
 }
diff --git a/sdk/trace/provider.go b/sdk/trace/provider.go
index fe4b8a7a..6b596e4d 100644
--- a/sdk/trace/provider.go
+++ b/sdk/trace/provider.go
@@ -21,7 +21,7 @@ import (
 	export "go.opentelemetry.io/otel/sdk/export/trace"
 	"go.opentelemetry.io/otel/sdk/resource"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	apitrace "go.opentelemetry.io/otel/api/trace"
 )
 
@@ -197,7 +197,7 @@ func WithConfig(config Config) ProviderOption {
 
 // WithResourceAttributes option sets the resource attributes to the provider.
 // Resource is added to the span when it is started.
-func WithResourceAttributes(attrs ...core.KeyValue) ProviderOption {
+func WithResourceAttributes(attrs ...kv.KeyValue) ProviderOption {
 	return func(opts *ProviderOptions) {
 		opts.config.Resource = resource.New(attrs...)
 	}
diff --git a/sdk/trace/sampling.go b/sdk/trace/sampling.go
index 3f33a473..8cf8248d 100644
--- a/sdk/trace/sampling.go
+++ b/sdk/trace/sampling.go
@@ -18,7 +18,7 @@ import (
 	"encoding/binary"
 	"fmt"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	api "go.opentelemetry.io/otel/api/trace"
 )
 
@@ -36,7 +36,7 @@ type SamplingParameters struct {
 	Name            string
 	HasRemoteParent bool
 	Kind            api.SpanKind
-	Attributes      []core.KeyValue
+	Attributes      []kv.KeyValue
 	Links           []api.Link
 }
 
@@ -53,7 +53,7 @@ const (
 // SamplingResult conveys a SamplingDecision and a set of Attributes.
 type SamplingResult struct {
 	Decision   SamplingDecision
-	Attributes []core.KeyValue
+	Attributes []kv.KeyValue
 }
 
 type probabilitySampler struct {
diff --git a/sdk/trace/span.go b/sdk/trace/span.go
index 9753968d..50772115 100644
--- a/sdk/trace/span.go
+++ b/sdk/trace/span.go
@@ -23,16 +23,15 @@ import (
 
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	apitrace "go.opentelemetry.io/otel/api/trace"
 	export "go.opentelemetry.io/otel/sdk/export/trace"
 	"go.opentelemetry.io/otel/sdk/internal"
 )
 
 const (
-	errorTypeKey    = core.Key("error.type")
-	errorMessageKey = core.Key("error.message")
+	errorTypeKey    = kv.Key("error.type")
+	errorMessageKey = kv.Key("error.message")
 	errorEventName  = "error"
 )
 
@@ -94,7 +93,7 @@ func (s *span) SetStatus(code codes.Code, msg string) {
 	s.mu.Unlock()
 }
 
-func (s *span) SetAttributes(attributes ...core.KeyValue) {
+func (s *span) SetAttributes(attributes ...kv.KeyValue) {
 	if !s.IsRecording() {
 		return
 	}
@@ -102,7 +101,7 @@ func (s *span) SetAttributes(attributes ...core.KeyValue) {
 }
 
 func (s *span) SetAttribute(k string, v interface{}) {
-	s.SetAttributes(key.Infer(k, v))
+	s.SetAttributes(kv.Infer(k, v))
 }
 
 func (s *span) End(options ...apitrace.EndOption) {
@@ -177,21 +176,21 @@ func (s *span) Tracer() apitrace.Tracer {
 	return s.tracer
 }
 
-func (s *span) AddEvent(ctx context.Context, name string, attrs ...core.KeyValue) {
+func (s *span) AddEvent(ctx context.Context, name string, attrs ...kv.KeyValue) {
 	if !s.IsRecording() {
 		return
 	}
 	s.addEventWithTimestamp(time.Now(), name, attrs...)
 }
 
-func (s *span) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...core.KeyValue) {
+func (s *span) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...kv.KeyValue) {
 	if !s.IsRecording() {
 		return
 	}
 	s.addEventWithTimestamp(timestamp, name, attrs...)
 }
 
-func (s *span) addEventWithTimestamp(timestamp time.Time, name string, attrs ...core.KeyValue) {
+func (s *span) addEventWithTimestamp(timestamp time.Time, name string, attrs ...kv.KeyValue) {
 	s.mu.Lock()
 	defer s.mu.Unlock()
 	s.messageEvents.add(export.Event{
@@ -286,7 +285,7 @@ func (s *span) interfaceArrayToMessageEventArray() []export.Event {
 	return messageEventArr
 }
 
-func (s *span) copyToCappedAttributes(attributes ...core.KeyValue) {
+func (s *span) copyToCappedAttributes(attributes ...kv.KeyValue) {
 	s.mu.Lock()
 	defer s.mu.Unlock()
 	for _, a := range attributes {
@@ -374,7 +373,7 @@ type samplingData struct {
 	name         string
 	cfg          *Config
 	span         *span
-	attributes   []core.KeyValue
+	attributes   []kv.KeyValue
 	links        []apitrace.Link
 	kind         apitrace.SpanKind
 }


Test patch:
diff --git a/api/core/key_test.go b/api/core/key_test.go
deleted file mode 100644
index 8c5f4b9f..00000000
--- a/api/core/key_test.go
+++ /dev/null
@@ -1,275 +0,0 @@
-// Copyright The OpenTelemetry Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package core_test
-
-import (
-	"encoding/json"
-	"testing"
-	"unsafe"
-
-	"github.com/google/go-cmp/cmp"
-	"github.com/stretchr/testify/require"
-
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
-)
-
-func TestValue(t *testing.T) {
-	k := core.Key("test")
-	bli := getBitlessInfo(42)
-	for _, testcase := range []struct {
-		name      string
-		value     core.Value
-		wantType  core.ValueType
-		wantValue interface{}
-	}{
-		{
-			name:      "Key.Bool() correctly returns keys's internal bool value",
-			value:     k.Bool(true).Value,
-			wantType:  core.BOOL,
-			wantValue: true,
-		},
-		{
-			name:      "Key.Int64() correctly returns keys's internal int64 value",
-			value:     k.Int64(42).Value,
-			wantType:  core.INT64,
-			wantValue: int64(42),
-		},
-		{
-			name:      "Key.Uint64() correctly returns keys's internal uint64 value",
-			value:     k.Uint64(42).Value,
-			wantType:  core.UINT64,
-			wantValue: uint64(42),
-		},
-		{
-			name:      "Key.Float64() correctly returns keys's internal float64 value",
-			value:     k.Float64(42.1).Value,
-			wantType:  core.FLOAT64,
-			wantValue: 42.1,
-		},
-		{
-			name:      "Key.Int32() correctly returns keys's internal int32 value",
-			value:     k.Int32(42).Value,
-			wantType:  core.INT32,
-			wantValue: int32(42),
-		},
-		{
-			name:      "Key.Uint32() correctly returns keys's internal uint32 value",
-			value:     k.Uint32(42).Value,
-			wantType:  core.UINT32,
-			wantValue: uint32(42),
-		},
-		{
-			name:      "Key.Float32() correctly returns keys's internal float32 value",
-			value:     k.Float32(42.1).Value,
-			wantType:  core.FLOAT32,
-			wantValue: float32(42.1),
-		},
-		{
-			name:      "Key.String() correctly returns keys's internal string value",
-			value:     k.String("foo").Value,
-			wantType:  core.STRING,
-			wantValue: "foo",
-		},
-		{
-			name:      "Key.Int() correctly returns keys's internal signed integral value",
-			value:     k.Int(bli.intValue).Value,
-			wantType:  bli.signedType,
-			wantValue: bli.signedValue,
-		},
-		{
-			name:      "Key.Uint() correctly returns keys's internal unsigned integral value",
-			value:     k.Uint(bli.uintValue).Value,
-			wantType:  bli.unsignedType,
-			wantValue: bli.unsignedValue,
-		},
-	} {
-		t.Logf("Running test case %s", testcase.name)
-		if testcase.value.Type() != testcase.wantType {
-			t.Errorf("wrong value type, got %#v, expected %#v", testcase.value.Type(), testcase.wantType)
-		}
-		got := testcase.value.AsInterface()
-		if diff := cmp.Diff(testcase.wantValue, got); diff != "" {
-			t.Errorf("+got, -want: %s", diff)
-		}
-	}
-}
-
-type bitlessInfo struct {
-	intValue      int
-	uintValue     uint
-	signedType    core.ValueType
-	unsignedType  core.ValueType
-	signedValue   interface{}
-	unsignedValue interface{}
-}
-
-func getBitlessInfo(i int) bitlessInfo {
-	if unsafe.Sizeof(i) == 4 {
-		return bitlessInfo{
-			intValue:      i,
-			uintValue:     uint(i),
-			signedType:    core.INT32,
-			unsignedType:  core.UINT32,
-			signedValue:   int32(i),
-			unsignedValue: uint32(i),
-		}
-	}
-	return bitlessInfo{
-		intValue:      i,
-		uintValue:     uint(i),
-		signedType:    core.INT64,
-		unsignedType:  core.UINT64,
-		signedValue:   int64(i),
-		unsignedValue: uint64(i),
-	}
-}
-
-func TestDefined(t *testing.T) {
-	for _, testcase := range []struct {
-		name string
-		k    core.Key
-		want bool
-	}{
-		{
-			name: "Key.Defined() returns true when len(v.Name) != 0",
-			k:    core.Key("foo"),
-			want: true,
-		},
-		{
-			name: "Key.Defined() returns false when len(v.Name) == 0",
-			k:    core.Key(""),
-			want: false,
-		},
-	} {
-		t.Run(testcase.name, func(t *testing.T) {
-			//func (k core.Key) Defined() bool {
-			have := testcase.k.Defined()
-			if have != testcase.want {
-				t.Errorf("Want: %v, but have: %v", testcase.want, have)
-			}
-		})
-	}
-}
-
-func TestJSONValue(t *testing.T) {
-	var kvs interface{} = [2]core.KeyValue{
-		key.String("A", "B"),
-		key.Int64("C", 1),
-	}
-
-	data, err := json.Marshal(kvs)
-	require.NoError(t, err)
-	require.Equal(t,
-		`[{"Key":"A","Value":{"Type":"STRING","Value":"B"}},{"Key":"C","Value":{"Type":"INT64","Value":1}}]`,
-		string(data))
-}
-
-func TestEmit(t *testing.T) {
-	for _, testcase := range []struct {
-		name string
-		v    core.Value
-		want string
-	}{
-		{
-			name: `test Key.Emit() can emit a string representing self.BOOL`,
-			v:    core.Bool(true),
-			want: "true",
-		},
-		{
-			name: `test Key.Emit() can emit a string representing self.INT32`,
-			v:    core.Int32(42),
-			want: "42",
-		},
-		{
-			name: `test Key.Emit() can emit a string representing self.INT64`,
-			v:    core.Int64(42),
-			want: "42",
-		},
-		{
-			name: `test Key.Emit() can emit a string representing self.UINT32`,
-			v:    core.Uint32(42),
-			want: "42",
-		},
-		{
-			name: `test Key.Emit() can emit a string representing self.UINT64`,
-			v:    core.Uint64(42),
-			want: "42",
-		},
-		{
-			name: `test Key.Emit() can emit a string representing self.FLOAT32`,
-			v:    core.Float32(42.1),
-			want: "42.1",
-		},
-		{
-			name: `test Key.Emit() can emit a string representing self.FLOAT64`,
-			v:    core.Float64(42.1),
-			want: "42.1",
-		},
-		{
-			name: `test Key.Emit() can emit a string representing self.STRING`,
-			v:    core.String("foo"),
-			want: "foo",
-		},
-	} {
-		t.Run(testcase.name, func(t *testing.T) {
-			//proto: func (v core.Value) Emit() string {
-			have := testcase.v.Emit()
-			if have != testcase.want {
-				t.Errorf("Want: %s, but have: %s", testcase.want, have)
-			}
-		})
-	}
-}
-
-func BenchmarkEmitBool(b *testing.B) {
-	b.ReportAllocs()
-	for i := 0; i < b.N; i++ {
-		n := core.Bool(i%2 == 0)
-		_ = n.Emit()
-	}
-}
-
-func BenchmarkEmitInt64(b *testing.B) {
-	b.ReportAllocs()
-	for i := 0; i < b.N; i++ {
-		n := core.Int64(int64(i))
-		_ = n.Emit()
-	}
-}
-
-func BenchmarkEmitUInt64(b *testing.B) {
-	b.ReportAllocs()
-	for i := 0; i < b.N; i++ {
-		n := core.Uint64(uint64(i))
-		_ = n.Emit()
-	}
-}
-
-func BenchmarkEmitFloat64(b *testing.B) {
-	b.ReportAllocs()
-	for i := 0; i < b.N; i++ {
-		n := core.Float64(float64(i))
-		_ = n.Emit()
-	}
-}
-
-func BenchmarkEmitFloat32(b *testing.B) {
-	b.ReportAllocs()
-	for i := 0; i < b.N; i++ {
-		n := core.Float32(float32(i))
-		_ = n.Emit()
-	}
-}
diff --git a/api/correlation/correlation_context_propagator_test.go b/api/correlation/correlation_context_propagator_test.go
index 5b4539a7..d422653c 100644
--- a/api/correlation/correlation_context_propagator_test.go
+++ b/api/correlation/correlation_context_propagator_test.go
@@ -20,11 +20,12 @@ import (
 	"strings"
 	"testing"
 
+	"go.opentelemetry.io/otel/api/kv/value"
+
 	"github.com/google/go-cmp/cmp"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/correlation"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/propagation"
 )
 
@@ -33,54 +34,54 @@ func TestExtractValidDistributedContextFromHTTPReq(t *testing.T) {
 	tests := []struct {
 		name    string
 		header  string
-		wantKVs []core.KeyValue
+		wantKVs []kv.KeyValue
 	}{
 		{
 			name:   "valid w3cHeader",
 			header: "key1=val1,key2=val2",
-			wantKVs: []core.KeyValue{
-				key.New("key1").String("val1"),
-				key.New("key2").String("val2"),
+			wantKVs: []kv.KeyValue{
+				kv.NewKey("key1").String("val1"),
+				kv.NewKey("key2").String("val2"),
 			},
 		},
 		{
 			name:   "valid w3cHeader with spaces",
 			header: "key1 =   val1,  key2 =val2   ",
-			wantKVs: []core.KeyValue{
-				key.New("key1").String("val1"),
-				key.New("key2").String("val2"),
+			wantKVs: []kv.KeyValue{
+				kv.NewKey("key1").String("val1"),
+				kv.NewKey("key2").String("val2"),
 			},
 		},
 		{
 			name:   "valid w3cHeader with properties",
 			header: "key1=val1,key2=val2;prop=1",
-			wantKVs: []core.KeyValue{
-				key.New("key1").String("val1"),
-				key.New("key2").String("val2;prop=1"),
+			wantKVs: []kv.KeyValue{
+				kv.NewKey("key1").String("val1"),
+				kv.NewKey("key2").String("val2;prop=1"),
 			},
 		},
 		{
 			name:   "valid header with url-escaped comma",
 			header: "key1=val1,key2=val2%2Cval3",
-			wantKVs: []core.KeyValue{
-				key.New("key1").String("val1"),
-				key.New("key2").String("val2,val3"),
+			wantKVs: []kv.KeyValue{
+				kv.NewKey("key1").String("val1"),
+				kv.NewKey("key2").String("val2,val3"),
 			},
 		},
 		{
 			name:   "valid header with an invalid header",
 			header: "key1=val1,key2=val2,a,val3",
-			wantKVs: []core.KeyValue{
-				key.New("key1").String("val1"),
-				key.New("key2").String("val2"),
+			wantKVs: []kv.KeyValue{
+				kv.NewKey("key1").String("val1"),
+				kv.NewKey("key2").String("val2"),
 			},
 		},
 		{
 			name:   "valid header with no value",
 			header: "key1=,key2=val2",
-			wantKVs: []core.KeyValue{
-				key.New("key1").String(""),
-				key.New("key2").String("val2"),
+			wantKVs: []kv.KeyValue{
+				kv.NewKey("key1").String(""),
+				kv.NewKey("key2").String("val2"),
 			},
 		},
 	}
@@ -102,9 +103,9 @@ func TestExtractValidDistributedContextFromHTTPReq(t *testing.T) {
 				)
 			}
 			totalDiff := ""
-			wantCorCtx.Foreach(func(kv core.KeyValue) bool {
-				val, _ := gotCorCtx.Value(kv.Key)
-				diff := cmp.Diff(kv, core.KeyValue{Key: kv.Key, Value: val}, cmp.AllowUnexported(core.Value{}))
+			wantCorCtx.Foreach(func(keyValue kv.KeyValue) bool {
+				val, _ := gotCorCtx.Value(keyValue.Key)
+				diff := cmp.Diff(keyValue, kv.KeyValue{Key: keyValue.Key, Value: val}, cmp.AllowUnexported(value.Value{}))
 				if diff != "" {
 					totalDiff += diff + "\n"
 				}
@@ -149,38 +150,38 @@ func TestInjectCorrelationContextToHTTPReq(t *testing.T) {
 	props := propagation.New(propagation.WithInjectors(propagator))
 	tests := []struct {
 		name         string
-		kvs          []core.KeyValue
+		kvs          []kv.KeyValue
 		wantInHeader []string
 		wantedLen    int
 	}{
 		{
 			name: "two simple values",
-			kvs: []core.KeyValue{
-				key.New("key1").String("val1"),
-				key.New("key2").String("val2"),
+			kvs: []kv.KeyValue{
+				kv.NewKey("key1").String("val1"),
+				kv.NewKey("key2").String("val2"),
 			},
 			wantInHeader: []string{"key1=val1", "key2=val2"},
 		},
 		{
 			name: "two values with escaped chars",
-			kvs: []core.KeyValue{
-				key.New("key1").String("val1,val2"),
-				key.New("key2").String("val3=4"),
+			kvs: []kv.KeyValue{
+				kv.NewKey("key1").String("val1,val2"),
+				kv.NewKey("key2").String("val3=4"),
 			},
 			wantInHeader: []string{"key1=val1%2Cval2", "key2=val3%3D4"},
 		},
 		{
 			name: "values of non-string types",
-			kvs: []core.KeyValue{
-				key.New("key1").Bool(true),
-				key.New("key2").Int(123),
-				key.New("key3").Int64(123),
-				key.New("key4").Int32(123),
-				key.New("key5").Uint(123),
-				key.New("key6").Uint32(123),
-				key.New("key7").Uint64(123),
-				key.New("key8").Float64(123.567),
-				key.New("key9").Float32(123.567),
+			kvs: []kv.KeyValue{
+				kv.NewKey("key1").Bool(true),
+				kv.NewKey("key2").Int(123),
+				kv.NewKey("key3").Int64(123),
+				kv.NewKey("key4").Int32(123),
+				kv.NewKey("key5").Uint(123),
+				kv.NewKey("key6").Uint32(123),
+				kv.NewKey("key7").Uint64(123),
+				kv.NewKey("key8").Float64(123.567),
+				kv.NewKey("key9").Float32(123.567),
 			},
 			wantInHeader: []string{
 				"key1=true",
diff --git a/api/correlation/map_test.go b/api/correlation/map_test.go
index de0db6c6..cc8e24e1 100644
--- a/api/correlation/map_test.go
+++ b/api/correlation/map_test.go
@@ -18,15 +18,16 @@ import (
 	"fmt"
 	"testing"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv/value"
+
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 type testCase struct {
 	name    string
 	value   MapUpdate
 	init    []int
-	wantKVs []core.KeyValue
+	wantKVs []kv.KeyValue
 }
 
 func TestMap(t *testing.T) {
@@ -47,7 +48,7 @@ func TestMap(t *testing.T) {
 			}
 		}
 		// test Foreach()
-		got.Foreach(func(kv core.KeyValue) bool {
+		got.Foreach(func(kv kv.KeyValue) bool {
 			for _, want := range testcase.wantKVs {
 				if kv == want {
 					return false
@@ -85,193 +86,193 @@ func TestSizeComputation(t *testing.T) {
 func getTestCases() []testCase {
 	return []testCase{
 		{
-			name: "New map with MultiKV",
-			value: MapUpdate{MultiKV: []core.KeyValue{
-				key.Int64("key1", 1),
-				key.String("key2", "val2")},
+			name: "NewKey map with MultiKV",
+			value: MapUpdate{MultiKV: []kv.KeyValue{
+				kv.Int64("key1", 1),
+				kv.String("key2", "val2")},
 			},
 			init: []int{},
-			wantKVs: []core.KeyValue{
-				key.Int64("key1", 1),
-				key.String("key2", "val2"),
+			wantKVs: []kv.KeyValue{
+				kv.Int64("key1", 1),
+				kv.String("key2", "val2"),
 			},
 		},
 		{
-			name:  "New map with SingleKV",
-			value: MapUpdate{SingleKV: key.String("key1", "val1")},
+			name:  "NewKey map with SingleKV",
+			value: MapUpdate{SingleKV: kv.String("key1", "val1")},
 			init:  []int{},
-			wantKVs: []core.KeyValue{
-				key.String("key1", "val1"),
+			wantKVs: []kv.KeyValue{
+				kv.String("key1", "val1"),
 			},
 		},
 		{
-			name: "New map with both add fields",
-			value: MapUpdate{SingleKV: key.Int64("key1", 3),
-				MultiKV: []core.KeyValue{
-					key.String("key1", ""),
-					key.String("key2", "val2")},
+			name: "NewKey map with both add fields",
+			value: MapUpdate{SingleKV: kv.Int64("key1", 3),
+				MultiKV: []kv.KeyValue{
+					kv.String("key1", ""),
+					kv.String("key2", "val2")},
 			},
 			init: []int{},
-			wantKVs: []core.KeyValue{
-				key.String("key1", ""),
-				key.String("key2", "val2"),
+			wantKVs: []kv.KeyValue{
+				kv.String("key1", ""),
+				kv.String("key2", "val2"),
 			},
 		},
 		{
-			name:    "New map with empty MapUpdate",
+			name:    "NewKey map with empty MapUpdate",
 			value:   MapUpdate{},
 			init:    []int{},
-			wantKVs: []core.KeyValue{},
+			wantKVs: []kv.KeyValue{},
 		},
 		{
-			name:    "New map with DropSingleK",
-			value:   MapUpdate{DropSingleK: core.Key("key1")},
+			name:    "NewKey map with DropSingleK",
+			value:   MapUpdate{DropSingleK: kv.Key("key1")},
 			init:    []int{},
-			wantKVs: []core.KeyValue{},
+			wantKVs: []kv.KeyValue{},
 		},
 		{
-			name: "New map with DropMultiK",
-			value: MapUpdate{DropMultiK: []core.Key{
-				core.Key("key1"), core.Key("key2"),
+			name: "NewKey map with DropMultiK",
+			value: MapUpdate{DropMultiK: []kv.Key{
+				kv.Key("key1"), kv.Key("key2"),
 			}},
 			init:    []int{},
-			wantKVs: []core.KeyValue{},
+			wantKVs: []kv.KeyValue{},
 		},
 		{
-			name: "New map with both drop fields",
+			name: "NewKey map with both drop fields",
 			value: MapUpdate{
-				DropSingleK: core.Key("key1"),
-				DropMultiK: []core.Key{
-					core.Key("key1"),
-					core.Key("key2"),
+				DropSingleK: kv.Key("key1"),
+				DropMultiK: []kv.Key{
+					kv.Key("key1"),
+					kv.Key("key2"),
 				},
 			},
 			init:    []int{},
-			wantKVs: []core.KeyValue{},
+			wantKVs: []kv.KeyValue{},
 		},
 		{
-			name: "New map with all fields",
+			name: "NewKey map with all fields",
 			value: MapUpdate{
-				DropSingleK: core.Key("key1"),
-				DropMultiK: []core.Key{
-					core.Key("key1"),
-					core.Key("key2"),
+				DropSingleK: kv.Key("key1"),
+				DropMultiK: []kv.Key{
+					kv.Key("key1"),
+					kv.Key("key2"),
 				},
-				SingleKV: key.String("key4", "val4"),
-				MultiKV: []core.KeyValue{
-					key.String("key1", ""),
-					key.String("key2", "val2"),
-					key.String("key3", "val3"),
+				SingleKV: kv.String("key4", "val4"),
+				MultiKV: []kv.KeyValue{
+					kv.String("key1", ""),
+					kv.String("key2", "val2"),
+					kv.String("key3", "val3"),
 				},
 			},
 			init: []int{},
-			wantKVs: []core.KeyValue{
-				key.String("key1", ""),
-				key.String("key2", "val2"),
-				key.String("key3", "val3"),
-				key.String("key4", "val4"),
+			wantKVs: []kv.KeyValue{
+				kv.String("key1", ""),
+				kv.String("key2", "val2"),
+				kv.String("key3", "val3"),
+				kv.String("key4", "val4"),
 			},
 		},
 		{
 			name: "Existing map with MultiKV",
-			value: MapUpdate{MultiKV: []core.KeyValue{
-				key.Int64("key1", 1),
-				key.String("key2", "val2")},
+			value: MapUpdate{MultiKV: []kv.KeyValue{
+				kv.Int64("key1", 1),
+				kv.String("key2", "val2")},
 			},
 			init: []int{5},
-			wantKVs: []core.KeyValue{
-				key.Int64("key1", 1),
-				key.String("key2", "val2"),
-				key.Int("key5", 5),
+			wantKVs: []kv.KeyValue{
+				kv.Int64("key1", 1),
+				kv.String("key2", "val2"),
+				kv.Int("key5", 5),
 			},
 		},
 		{
 			name:  "Existing map with SingleKV",
-			value: MapUpdate{SingleKV: key.String("key1", "val1")},
+			value: MapUpdate{SingleKV: kv.String("key1", "val1")},
 			init:  []int{5},
-			wantKVs: []core.KeyValue{
-				key.String("key1", "val1"),
-				key.Int("key5", 5),
+			wantKVs: []kv.KeyValue{
+				kv.String("key1", "val1"),
+				kv.Int("key5", 5),
 			},
 		},
 		{
 			name: "Existing map with both add fields",
-			value: MapUpdate{SingleKV: key.Int64("key1", 3),
-				MultiKV: []core.KeyValue{
-					key.String("key1", ""),
-					key.String("key2", "val2")},
+			value: MapUpdate{SingleKV: kv.Int64("key1", 3),
+				MultiKV: []kv.KeyValue{
+					kv.String("key1", ""),
+					kv.String("key2", "val2")},
 			},
 			init: []int{5},
-			wantKVs: []core.KeyValue{
-				key.String("key1", ""),
-				key.String("key2", "val2"),
-				key.Int("key5", 5),
+			wantKVs: []kv.KeyValue{
+				kv.String("key1", ""),
+				kv.String("key2", "val2"),
+				kv.Int("key5", 5),
 			},
 		},
 		{
 			name:  "Existing map with empty MapUpdate",
 			value: MapUpdate{},
 			init:  []int{5},
-			wantKVs: []core.KeyValue{
-				key.Int("key5", 5),
+			wantKVs: []kv.KeyValue{
+				kv.Int("key5", 5),
 			},
 		},
 		{
 			name:  "Existing map with DropSingleK",
-			value: MapUpdate{DropSingleK: core.Key("key1")},
+			value: MapUpdate{DropSingleK: kv.Key("key1")},
 			init:  []int{1, 5},
-			wantKVs: []core.KeyValue{
-				key.Int("key5", 5),
+			wantKVs: []kv.KeyValue{
+				kv.Int("key5", 5),
 			},
 		},
 		{
 			name: "Existing map with DropMultiK",
-			value: MapUpdate{DropMultiK: []core.Key{
-				core.Key("key1"), core.Key("key2"),
+			value: MapUpdate{DropMultiK: []kv.Key{
+				kv.Key("key1"), kv.Key("key2"),
 			}},
 			init: []int{1, 5},
-			wantKVs: []core.KeyValue{
-				key.Int("key5", 5),
+			wantKVs: []kv.KeyValue{
+				kv.Int("key5", 5),
 			},
 		},
 		{
 			name: "Existing map with both drop fields",
 			value: MapUpdate{
-				DropSingleK: core.Key("key1"),
-				DropMultiK: []core.Key{
-					core.Key("key1"),
-					core.Key("key2"),
+				DropSingleK: kv.Key("key1"),
+				DropMultiK: []kv.Key{
+					kv.Key("key1"),
+					kv.Key("key2"),
 				},
 			},
 			init: []int{1, 2, 5},
-			wantKVs: []core.KeyValue{
-				key.Int("key5", 5),
+			wantKVs: []kv.KeyValue{
+				kv.Int("key5", 5),
 			},
 		},
 		{
 			name: "Existing map with all the fields",
 			value: MapUpdate{
-				DropSingleK: core.Key("key1"),
-				DropMultiK: []core.Key{
-					core.Key("key1"),
-					core.Key("key2"),
-					core.Key("key5"),
-					core.Key("key6"),
+				DropSingleK: kv.Key("key1"),
+				DropMultiK: []kv.Key{
+					kv.Key("key1"),
+					kv.Key("key2"),
+					kv.Key("key5"),
+					kv.Key("key6"),
 				},
-				SingleKV: key.String("key4", "val4"),
-				MultiKV: []core.KeyValue{
-					key.String("key1", ""),
-					key.String("key2", "val2"),
-					key.String("key3", "val3"),
+				SingleKV: kv.String("key4", "val4"),
+				MultiKV: []kv.KeyValue{
+					kv.String("key1", ""),
+					kv.String("key2", "val2"),
+					kv.String("key3", "val3"),
 				},
 			},
 			init: []int{5, 6, 7},
-			wantKVs: []core.KeyValue{
-				key.String("key1", ""),
-				key.String("key2", "val2"),
-				key.String("key3", "val3"),
-				key.String("key4", "val4"),
-				key.Int("key7", 7),
+			wantKVs: []kv.KeyValue{
+				kv.String("key1", ""),
+				kv.String("key2", "val2"),
+				kv.String("key3", "val3"),
+				kv.String("key4", "val4"),
+				kv.Int("key7", 7),
 			},
 		},
 	}
@@ -280,7 +281,7 @@ func getTestCases() []testCase {
 func makeTestMap(ints []int) Map {
 	r := make(rawMap, len(ints))
 	for _, v := range ints {
-		r[core.Key(fmt.Sprintf("key%d", v))] = core.Int(v)
+		r[kv.Key(fmt.Sprintf("key%d", v))] = value.Int(v)
 	}
 	return newMap(r)
 }
diff --git a/api/global/internal/benchmark_test.go b/api/global/internal/benchmark_test.go
index 352007ac..66a3728d 100644
--- a/api/global/internal/benchmark_test.go
+++ b/api/global/internal/benchmark_test.go
@@ -19,10 +19,9 @@ import (
 	"strings"
 	"testing"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/global"
 	"go.opentelemetry.io/otel/api/global/internal"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 	"go.opentelemetry.io/otel/api/trace"
 	export "go.opentelemetry.io/otel/sdk/export/metric"
@@ -91,7 +90,7 @@ func BenchmarkGlobalInt64CounterAddNoSDK(b *testing.B) {
 	internal.ResetForTest()
 	ctx := context.Background()
 	sdk := global.Meter("test")
-	labs := []core.KeyValue{key.String("A", "B")}
+	labs := []kv.KeyValue{kv.String("A", "B")}
 	cnt := Must(sdk).NewInt64Counter("int64.counter")
 
 	b.ResetTimer()
@@ -110,7 +109,7 @@ func BenchmarkGlobalInt64CounterAddWithSDK(b *testing.B) {
 
 	global.SetMeterProvider(fix)
 
-	labs := []core.KeyValue{key.String("A", "B")}
+	labs := []kv.KeyValue{kv.String("A", "B")}
 	cnt := Must(sdk).NewInt64Counter("int64.counter")
 
 	b.ResetTimer()
diff --git a/api/global/internal/meter_test.go b/api/global/internal/meter_test.go
index 41066689..070e6522 100644
--- a/api/global/internal/meter_test.go
+++ b/api/global/internal/meter_test.go
@@ -22,12 +22,13 @@ import (
 	"io/ioutil"
 	"testing"
 
+	"go.opentelemetry.io/otel/api/kv/value"
+
 	"github.com/stretchr/testify/require"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/global"
 	"go.opentelemetry.io/otel/api/global/internal"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 	"go.opentelemetry.io/otel/exporters/metric/stdout"
 	metrictest "go.opentelemetry.io/otel/internal/metric"
@@ -37,7 +38,7 @@ import (
 type measured struct {
 	Name        string
 	LibraryName string
-	Labels      map[core.Key]core.Value
+	Labels      map[kv.Key]value.Value
 	Number      metric.Number
 }
 
@@ -56,8 +57,8 @@ func asStructs(batches []metrictest.Batch) []measured {
 	return r
 }
 
-func asMap(kvs ...core.KeyValue) map[core.Key]core.Value {
-	m := map[core.Key]core.Value{}
+func asMap(kvs ...kv.KeyValue) map[kv.Key]value.Value {
+	m := map[kv.Key]value.Value{}
 	for _, kv := range kvs {
 		m[kv.Key] = kv.Value
 	}
@@ -73,9 +74,9 @@ func TestDirect(t *testing.T) {
 	ctx := context.Background()
 	meter1 := global.Meter("test1")
 	meter2 := global.Meter("test2")
-	labels1 := []core.KeyValue{key.String("A", "B")}
-	labels2 := []core.KeyValue{key.String("C", "D")}
-	labels3 := []core.KeyValue{key.String("E", "F")}
+	labels1 := []kv.KeyValue{kv.String("A", "B")}
+	labels2 := []kv.KeyValue{kv.String("C", "D")}
+	labels3 := []kv.KeyValue{kv.String("E", "F")}
 
 	counter := Must(meter1).NewInt64Counter("test.counter")
 	counter.Add(ctx, 1, labels1...)
@@ -166,7 +167,7 @@ func TestBound(t *testing.T) {
 	// vs. the above, to cover all the instruments.
 	ctx := context.Background()
 	glob := global.Meter("test")
-	labels1 := []core.KeyValue{key.String("A", "B")}
+	labels1 := []kv.KeyValue{kv.String("A", "B")}
 
 	counter := Must(glob).NewFloat64Counter("test.counter")
 	boundC := counter.Bind(labels1...)
@@ -210,7 +211,7 @@ func TestUnbind(t *testing.T) {
 	internal.ResetForTest()
 
 	glob := global.Meter("test")
-	labels1 := []core.KeyValue{key.String("A", "B")}
+	labels1 := []kv.KeyValue{kv.String("A", "B")}
 
 	counter := Must(glob).NewFloat64Counter("test.counter")
 	boundC := counter.Bind(labels1...)
@@ -227,7 +228,7 @@ func TestDefaultSDK(t *testing.T) {
 
 	ctx := context.Background()
 	meter1 := global.Meter("builtin")
-	labels1 := []core.KeyValue{key.String("A", "B")}
+	labels1 := []kv.KeyValue{kv.String("A", "B")}
 
 	counter := Must(meter1).NewInt64Counter("test.builtin")
 	counter.Add(ctx, 1, labels1...)
diff --git a/api/key/benchmark_test.go b/api/kv/benchmark_test.go
similarity index 90%
rename from api/key/benchmark_test.go
rename to api/kv/benchmark_test.go
index d0e92401..a258e06a 100644
--- a/api/key/benchmark_test.go
+++ b/api/kv/benchmark_test.go
@@ -12,14 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package key_test
+package kv_test
 
 import (
 	"context"
 	"testing"
 
+	"go.opentelemetry.io/otel/api/kv"
+
 	"go.opentelemetry.io/otel/api/global"
-	"go.opentelemetry.io/otel/api/key"
 	"go.opentelemetry.io/otel/api/trace"
 	sdktrace "go.opentelemetry.io/otel/sdk/trace"
 )
@@ -35,7 +36,7 @@ func getSpan() trace.Span {
 
 func BenchmarkKeyInfer(b *testing.B) {
 	for i := 0; i < b.N; i++ {
-		key.Infer("Attr", int(256))
+		kv.Infer("Attr", int(256))
 	}
 }
 
@@ -46,7 +47,7 @@ func BenchmarkMultiNoKeyInference(b *testing.B) {
 	b.ResetTimer()
 
 	for i := 0; i < b.N; i++ {
-		sp.SetAttributes(key.Int("Attr", 1))
+		sp.SetAttributes(kv.Int("Attr", 1))
 	}
 }
 
@@ -57,7 +58,7 @@ func BenchmarkMultiWithKeyInference(b *testing.B) {
 	b.ResetTimer()
 
 	for i := 0; i < b.N; i++ {
-		sp.SetAttributes(key.Infer("Attr", 1))
+		sp.SetAttributes(kv.Infer("Attr", 1))
 	}
 }
 
diff --git a/api/kv/key_test.go b/api/kv/key_test.go
new file mode 100644
index 00000000..277750e0
--- /dev/null
+++ b/api/kv/key_test.go
@@ -0,0 +1,163 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kv_test
+
+import (
+	"encoding/json"
+	"testing"
+
+	"go.opentelemetry.io/otel/api/kv"
+
+	"github.com/stretchr/testify/require"
+
+	"go.opentelemetry.io/otel/api/kv/value"
+)
+
+func TestDefined(t *testing.T) {
+	for _, testcase := range []struct {
+		name string
+		k    kv.Key
+		want bool
+	}{
+		{
+			name: "Key.Defined() returns true when len(v.Name) != 0",
+			k:    kv.Key("foo"),
+			want: true,
+		},
+		{
+			name: "Key.Defined() returns false when len(v.Name) == 0",
+			k:    kv.Key(""),
+			want: false,
+		},
+	} {
+		t.Run(testcase.name, func(t *testing.T) {
+			//func (k kv.Key) Defined() bool {
+			have := testcase.k.Defined()
+			if have != testcase.want {
+				t.Errorf("Want: %v, but have: %v", testcase.want, have)
+			}
+		})
+	}
+}
+
+func TestJSONValue(t *testing.T) {
+	var kvs interface{} = [2]kv.KeyValue{
+		kv.String("A", "B"),
+		kv.Int64("C", 1),
+	}
+
+	data, err := json.Marshal(kvs)
+	require.NoError(t, err)
+	require.Equal(t,
+		`[{"Key":"A","Value":{"Type":"STRING","Value":"B"}},{"Key":"C","Value":{"Type":"INT64","Value":1}}]`,
+		string(data))
+}
+
+func TestEmit(t *testing.T) {
+	for _, testcase := range []struct {
+		name string
+		v    value.Value
+		want string
+	}{
+		{
+			name: `test Key.Emit() can emit a string representing self.BOOL`,
+			v:    value.Bool(true),
+			want: "true",
+		},
+		{
+			name: `test Key.Emit() can emit a string representing self.INT32`,
+			v:    value.Int32(42),
+			want: "42",
+		},
+		{
+			name: `test Key.Emit() can emit a string representing self.INT64`,
+			v:    value.Int64(42),
+			want: "42",
+		},
+		{
+			name: `test Key.Emit() can emit a string representing self.UINT32`,
+			v:    value.Uint32(42),
+			want: "42",
+		},
+		{
+			name: `test Key.Emit() can emit a string representing self.UINT64`,
+			v:    value.Uint64(42),
+			want: "42",
+		},
+		{
+			name: `test Key.Emit() can emit a string representing self.FLOAT32`,
+			v:    value.Float32(42.1),
+			want: "42.1",
+		},
+		{
+			name: `test Key.Emit() can emit a string representing self.FLOAT64`,
+			v:    value.Float64(42.1),
+			want: "42.1",
+		},
+		{
+			name: `test Key.Emit() can emit a string representing self.STRING`,
+			v:    value.String("foo"),
+			want: "foo",
+		},
+	} {
+		t.Run(testcase.name, func(t *testing.T) {
+			//proto: func (v kv.Value) Emit() string {
+			have := testcase.v.Emit()
+			if have != testcase.want {
+				t.Errorf("Want: %s, but have: %s", testcase.want, have)
+			}
+		})
+	}
+}
+
+func BenchmarkEmitBool(b *testing.B) {
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		n := value.Bool(i%2 == 0)
+		_ = n.Emit()
+	}
+}
+
+func BenchmarkEmitInt64(b *testing.B) {
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		n := value.Int64(int64(i))
+		_ = n.Emit()
+	}
+}
+
+func BenchmarkEmitUInt64(b *testing.B) {
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		n := value.Uint64(uint64(i))
+		_ = n.Emit()
+	}
+}
+
+func BenchmarkEmitFloat64(b *testing.B) {
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		n := value.Float64(float64(i))
+		_ = n.Emit()
+	}
+}
+
+func BenchmarkEmitFloat32(b *testing.B) {
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		n := value.Float32(float32(i))
+		_ = n.Emit()
+	}
+}
diff --git a/api/key/key_test.go b/api/kv/kv_test.go
similarity index 63%
rename from api/key/key_test.go
rename to api/kv/kv_test.go
index 6c76d5f4..9d2ccf47 100644
--- a/api/key/key_test.go
+++ b/api/kv/kv_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package key_test
+package kv_test
 
 import (
 	"strings"
@@ -20,101 +20,101 @@ import (
 
 	"github.com/google/go-cmp/cmp"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
+	"go.opentelemetry.io/otel/api/kv/value"
 )
 
 func TestKeyValueConstructors(t *testing.T) {
 	tt := []struct {
 		name     string
-		actual   core.KeyValue
-		expected core.KeyValue
+		actual   kv.KeyValue
+		expected kv.KeyValue
 	}{
 		{
 			name:   "Bool",
-			actual: key.Bool("k1", true),
-			expected: core.KeyValue{
+			actual: kv.Bool("k1", true),
+			expected: kv.KeyValue{
 				Key:   "k1",
-				Value: core.Bool(true),
+				Value: value.Bool(true),
 			},
 		},
 		{
 			name:   "Int64",
-			actual: key.Int64("k1", 123),
-			expected: core.KeyValue{
+			actual: kv.Int64("k1", 123),
+			expected: kv.KeyValue{
 				Key:   "k1",
-				Value: core.Int64(123),
+				Value: value.Int64(123),
 			},
 		},
 		{
 			name:   "Uint64",
-			actual: key.Uint64("k1", 1),
-			expected: core.KeyValue{
+			actual: kv.Uint64("k1", 1),
+			expected: kv.KeyValue{
 				Key:   "k1",
-				Value: core.Uint64(1),
+				Value: value.Uint64(1),
 			},
 		},
 		{
 			name:   "Float64",
-			actual: key.Float64("k1", 123.5),
-			expected: core.KeyValue{
+			actual: kv.Float64("k1", 123.5),
+			expected: kv.KeyValue{
 				Key:   "k1",
-				Value: core.Float64(123.5),
+				Value: value.Float64(123.5),
 			},
 		},
 		{
 			name:   "Int32",
-			actual: key.Int32("k1", 123),
-			expected: core.KeyValue{
+			actual: kv.Int32("k1", 123),
+			expected: kv.KeyValue{
 				Key:   "k1",
-				Value: core.Int32(123),
+				Value: value.Int32(123),
 			},
 		},
 		{
 			name:   "Uint32",
-			actual: key.Uint32("k1", 123),
-			expected: core.KeyValue{
+			actual: kv.Uint32("k1", 123),
+			expected: kv.KeyValue{
 				Key:   "k1",
-				Value: core.Uint32(123),
+				Value: value.Uint32(123),
 			},
 		},
 		{
 			name:   "Float32",
-			actual: key.Float32("k1", 123.5),
-			expected: core.KeyValue{
+			actual: kv.Float32("k1", 123.5),
+			expected: kv.KeyValue{
 				Key:   "k1",
-				Value: core.Float32(123.5),
+				Value: value.Float32(123.5),
 			},
 		},
 		{
 			name:   "String",
-			actual: key.String("k1", "123.5"),
-			expected: core.KeyValue{
+			actual: kv.String("k1", "123.5"),
+			expected: kv.KeyValue{
 				Key:   "k1",
-				Value: core.String("123.5"),
+				Value: value.String("123.5"),
 			},
 		},
 		{
 			name:   "Int",
-			actual: key.Int("k1", 123),
-			expected: core.KeyValue{
+			actual: kv.Int("k1", 123),
+			expected: kv.KeyValue{
 				Key:   "k1",
-				Value: core.Int(123),
+				Value: value.Int(123),
 			},
 		},
 		{
 			name:   "Uint",
-			actual: key.Uint("k1", 123),
-			expected: core.KeyValue{
+			actual: kv.Uint("k1", 123),
+			expected: kv.KeyValue{
 				Key:   "k1",
-				Value: core.Uint(123),
+				Value: value.Uint(123),
 			},
 		},
 	}
 
 	for _, test := range tt {
 		t.Run(test.name, func(t *testing.T) {
-			if diff := cmp.Diff(test.actual, test.expected, cmp.AllowUnexported(core.Value{})); diff != "" {
+			if diff := cmp.Diff(test.actual, test.expected, cmp.AllowUnexported(value.Value{})); diff != "" {
 				t.Fatal(diff)
 			}
 		})
@@ -127,76 +127,76 @@ func TestInfer(t *testing.T) {
 	for _, testcase := range []struct {
 		key       string
 		value     interface{}
-		wantType  core.ValueType
+		wantType  value.Type
 		wantValue interface{}
 	}{
 		{
 			key:       "bool type inferred",
 			value:     true,
-			wantType:  core.BOOL,
+			wantType:  value.BOOL,
 			wantValue: true,
 		},
 		{
 			key:       "int64 type inferred",
 			value:     int64(42),
-			wantType:  core.INT64,
+			wantType:  value.INT64,
 			wantValue: int64(42),
 		},
 		{
 			key:       "uint64 type inferred",
 			value:     uint64(42),
-			wantType:  core.UINT64,
+			wantType:  value.UINT64,
 			wantValue: uint64(42),
 		},
 		{
 			key:       "float64 type inferred",
 			value:     float64(42.1),
-			wantType:  core.FLOAT64,
+			wantType:  value.FLOAT64,
 			wantValue: 42.1,
 		},
 		{
 			key:       "int32 type inferred",
 			value:     int32(42),
-			wantType:  core.INT32,
+			wantType:  value.INT32,
 			wantValue: int32(42),
 		},
 		{
 			key:       "uint32 type inferred",
 			value:     uint32(42),
-			wantType:  core.UINT32,
+			wantType:  value.UINT32,
 			wantValue: uint32(42),
 		},
 		{
 			key:       "float32 type inferred",
 			value:     float32(42.1),
-			wantType:  core.FLOAT32,
+			wantType:  value.FLOAT32,
 			wantValue: float32(42.1),
 		},
 		{
 			key:       "string type inferred",
 			value:     "foo",
-			wantType:  core.STRING,
+			wantType:  value.STRING,
 			wantValue: "foo",
 		},
 		{
 			key:       "stringer type inferred",
 			value:     builder,
-			wantType:  core.STRING,
+			wantType:  value.STRING,
 			wantValue: "foo",
 		},
 		{
 			key:       "unknown value serialized as %v",
 			value:     nil,
-			wantType:  core.STRING,
+			wantType:  value.STRING,
 			wantValue: "<nil>",
 		},
 	} {
 		t.Logf("Running test case %s", testcase.key)
-		kv := key.Infer(testcase.key, testcase.value)
-		if kv.Value.Type() != testcase.wantType {
-			t.Errorf("wrong value type, got %#v, expected %#v", kv.Value.Type(), testcase.wantType)
+		keyValue := kv.Infer(testcase.key, testcase.value)
+		if keyValue.Value.Type() != testcase.wantType {
+			t.Errorf("wrong value type, got %#v, expected %#v", keyValue.Value.Type(), testcase.wantType)
 		}
-		got := kv.Value.AsInterface()
+		got := keyValue.Value.AsInterface()
 		if diff := cmp.Diff(testcase.wantValue, got); diff != "" {
 			t.Errorf("+got, -want: %s", diff)
 		}
diff --git a/api/kv/value/value_test.go b/api/kv/value/value_test.go
new file mode 100644
index 00000000..9e225bdd
--- /dev/null
+++ b/api/kv/value/value_test.go
@@ -0,0 +1,137 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package value_test
+
+import (
+	"testing"
+	"unsafe"
+
+	"go.opentelemetry.io/otel/api/kv"
+
+	"github.com/google/go-cmp/cmp"
+
+	"go.opentelemetry.io/otel/api/kv/value"
+)
+
+func TestValue(t *testing.T) {
+	k := kv.Key("test")
+	bli := getBitlessInfo(42)
+	for _, testcase := range []struct {
+		name      string
+		value     value.Value
+		wantType  value.Type
+		wantValue interface{}
+	}{
+		{
+			name:      "Key.Bool() correctly returns keys's internal bool value",
+			value:     k.Bool(true).Value,
+			wantType:  value.BOOL,
+			wantValue: true,
+		},
+		{
+			name:      "Key.Int64() correctly returns keys's internal int64 value",
+			value:     k.Int64(42).Value,
+			wantType:  value.INT64,
+			wantValue: int64(42),
+		},
+		{
+			name:      "Key.Uint64() correctly returns keys's internal uint64 value",
+			value:     k.Uint64(42).Value,
+			wantType:  value.UINT64,
+			wantValue: uint64(42),
+		},
+		{
+			name:      "Key.Float64() correctly returns keys's internal float64 value",
+			value:     k.Float64(42.1).Value,
+			wantType:  value.FLOAT64,
+			wantValue: 42.1,
+		},
+		{
+			name:      "Key.Int32() correctly returns keys's internal int32 value",
+			value:     k.Int32(42).Value,
+			wantType:  value.INT32,
+			wantValue: int32(42),
+		},
+		{
+			name:      "Key.Uint32() correctly returns keys's internal uint32 value",
+			value:     k.Uint32(42).Value,
+			wantType:  value.UINT32,
+			wantValue: uint32(42),
+		},
+		{
+			name:      "Key.Float32() correctly returns keys's internal float32 value",
+			value:     k.Float32(42.1).Value,
+			wantType:  value.FLOAT32,
+			wantValue: float32(42.1),
+		},
+		{
+			name:      "Key.String() correctly returns keys's internal string value",
+			value:     k.String("foo").Value,
+			wantType:  value.STRING,
+			wantValue: "foo",
+		},
+		{
+			name:      "Key.Int() correctly returns keys's internal signed integral value",
+			value:     k.Int(bli.intValue).Value,
+			wantType:  bli.signedType,
+			wantValue: bli.signedValue,
+		},
+		{
+			name:      "Key.Uint() correctly returns keys's internal unsigned integral value",
+			value:     k.Uint(bli.uintValue).Value,
+			wantType:  bli.unsignedType,
+			wantValue: bli.unsignedValue,
+		},
+	} {
+		t.Logf("Running test case %s", testcase.name)
+		if testcase.value.Type() != testcase.wantType {
+			t.Errorf("wrong value type, got %#v, expected %#v", testcase.value.Type(), testcase.wantType)
+		}
+		got := testcase.value.AsInterface()
+		if diff := cmp.Diff(testcase.wantValue, got); diff != "" {
+			t.Errorf("+got, -want: %s", diff)
+		}
+	}
+}
+
+type bitlessInfo struct {
+	intValue      int
+	uintValue     uint
+	signedType    value.Type
+	unsignedType  value.Type
+	signedValue   interface{}
+	unsignedValue interface{}
+}
+
+func getBitlessInfo(i int) bitlessInfo {
+	if unsafe.Sizeof(i) == 4 {
+		return bitlessInfo{
+			intValue:      i,
+			uintValue:     uint(i),
+			signedType:    value.INT32,
+			unsignedType:  value.UINT32,
+			signedValue:   int32(i),
+			unsignedValue: uint32(i),
+		}
+	}
+	return bitlessInfo{
+		intValue:      i,
+		uintValue:     uint(i),
+		signedType:    value.INT64,
+		unsignedType:  value.UINT64,
+		signedValue:   int64(i),
+		unsignedValue: uint64(i),
+	}
+}
diff --git a/api/label/iterator_test.go b/api/label/iterator_test.go
index 5120541e..0548240f 100644
--- a/api/label/iterator_test.go
+++ b/api/label/iterator_test.go
@@ -17,15 +17,16 @@ package label_test
 import (
 	"testing"
 
+	"go.opentelemetry.io/otel/api/kv"
+
 	"github.com/stretchr/testify/require"
 
-	"go.opentelemetry.io/otel/api/key"
 	"go.opentelemetry.io/otel/api/label"
 )
 
 func TestIterator(t *testing.T) {
-	one := key.String("one", "1")
-	two := key.Int("two", 2)
+	one := kv.String("one", "1")
+	two := kv.Int("two", 2)
 	lbl := label.NewSet(one, two)
 	iter := lbl.Iter()
 	require.Equal(t, 2, iter.Len())
diff --git a/api/label/set_test.go b/api/label/set_test.go
index f8255b6b..84690b88 100644
--- a/api/label/set_test.go
+++ b/api/label/set_test.go
@@ -17,19 +17,18 @@ package label_test
 import (
 	"testing"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/label"
 
 	"github.com/stretchr/testify/require"
 )
 
 type testCase struct {
-	kvs      []core.KeyValue
+	kvs      []kv.KeyValue
 	encoding string
 }
 
-func expect(enc string, kvs ...core.KeyValue) testCase {
+func expect(enc string, kvs ...kv.KeyValue) testCase {
 	return testCase{
 		kvs:      kvs,
 		encoding: enc,
@@ -38,16 +37,16 @@ func expect(enc string, kvs ...core.KeyValue) testCase {
 
 func TestSetDedup(t *testing.T) {
 	cases := []testCase{
-		expect("A=B", key.String("A", "2"), key.String("A", "B")),
-		expect("A=B", key.String("A", "2"), key.Int("A", 1), key.String("A", "B")),
-		expect("A=B", key.String("A", "B"), key.String("A", "C"), key.String("A", "D"), key.String("A", "B")),
-
-		expect("A=B,C=D", key.String("A", "1"), key.String("C", "D"), key.String("A", "B")),
-		expect("A=B,C=D", key.String("A", "2"), key.String("A", "B"), key.String("C", "D")),
-		expect("A=B,C=D", key.Float64("C", 1.2), key.String("A", "2"), key.String("A", "B"), key.String("C", "D")),
-		expect("A=B,C=D", key.String("C", "D"), key.String("A", "B"), key.String("A", "C"), key.String("A", "D"), key.String("A", "B")),
-		expect("A=B,C=D", key.String("A", "B"), key.String("C", "D"), key.String("A", "C"), key.String("A", "D"), key.String("A", "B")),
-		expect("A=B,C=D", key.String("A", "B"), key.String("A", "C"), key.String("A", "D"), key.String("A", "B"), key.String("C", "D")),
+		expect("A=B", kv.String("A", "2"), kv.String("A", "B")),
+		expect("A=B", kv.String("A", "2"), kv.Int("A", 1), kv.String("A", "B")),
+		expect("A=B", kv.String("A", "B"), kv.String("A", "C"), kv.String("A", "D"), kv.String("A", "B")),
+
+		expect("A=B,C=D", kv.String("A", "1"), kv.String("C", "D"), kv.String("A", "B")),
+		expect("A=B,C=D", kv.String("A", "2"), kv.String("A", "B"), kv.String("C", "D")),
+		expect("A=B,C=D", kv.Float64("C", 1.2), kv.String("A", "2"), kv.String("A", "B"), kv.String("C", "D")),
+		expect("A=B,C=D", kv.String("C", "D"), kv.String("A", "B"), kv.String("A", "C"), kv.String("A", "D"), kv.String("A", "B")),
+		expect("A=B,C=D", kv.String("A", "B"), kv.String("C", "D"), kv.String("A", "C"), kv.String("A", "D"), kv.String("A", "B")),
+		expect("A=B,C=D", kv.String("A", "B"), kv.String("A", "C"), kv.String("A", "D"), kv.String("A", "B"), kv.String("C", "D")),
 	}
 	enc := label.DefaultEncoder()
 
@@ -55,7 +54,7 @@ func TestSetDedup(t *testing.T) {
 	d2s := map[label.Distinct][]string{}
 
 	for _, tc := range cases {
-		cpy := make([]core.KeyValue, len(tc.kvs))
+		cpy := make([]kv.KeyValue, len(tc.kvs))
 		copy(cpy, tc.kvs)
 		sl := label.NewSet(cpy...)
 
diff --git a/api/metric/api_test.go b/api/metric/api_test.go
index e75abdbb..820d286e 100644
--- a/api/metric/api_test.go
+++ b/api/metric/api_test.go
@@ -20,8 +20,7 @@ import (
 	"fmt"
 	"testing"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 	"go.opentelemetry.io/otel/api/unit"
 	mockTest "go.opentelemetry.io/otel/internal/metric"
@@ -98,7 +97,7 @@ func TestCounter(t *testing.T) {
 		mockSDK, meter := mockTest.NewMeter()
 		c := Must(meter).NewFloat64Counter("test.counter.float")
 		ctx := context.Background()
-		labels := []core.KeyValue{key.String("A", "B")}
+		labels := []kv.KeyValue{kv.String("A", "B")}
 		c.Add(ctx, 42, labels...)
 		boundInstrument := c.Bind(labels...)
 		boundInstrument.Add(ctx, 42)
@@ -110,7 +109,7 @@ func TestCounter(t *testing.T) {
 		mockSDK, meter := mockTest.NewMeter()
 		c := Must(meter).NewInt64Counter("test.counter.int")
 		ctx := context.Background()
-		labels := []core.KeyValue{key.String("A", "B"), key.String("C", "D")}
+		labels := []kv.KeyValue{kv.String("A", "B"), kv.String("C", "D")}
 		c.Add(ctx, 42, labels...)
 		boundInstrument := c.Bind(labels...)
 		boundInstrument.Add(ctx, 42)
@@ -125,7 +124,7 @@ func TestMeasure(t *testing.T) {
 		mockSDK, meter := mockTest.NewMeter()
 		m := Must(meter).NewFloat64Measure("test.measure.float")
 		ctx := context.Background()
-		labels := []core.KeyValue{}
+		labels := []kv.KeyValue{}
 		m.Record(ctx, 42, labels...)
 		boundInstrument := m.Bind(labels...)
 		boundInstrument.Record(ctx, 42)
@@ -137,7 +136,7 @@ func TestMeasure(t *testing.T) {
 		mockSDK, meter := mockTest.NewMeter()
 		m := Must(meter).NewInt64Measure("test.measure.int")
 		ctx := context.Background()
-		labels := []core.KeyValue{key.Int("I", 1)}
+		labels := []kv.KeyValue{kv.Int("I", 1)}
 		m.Record(ctx, 42, labels...)
 		boundInstrument := m.Bind(labels...)
 		boundInstrument.Record(ctx, 42)
@@ -149,7 +148,7 @@ func TestMeasure(t *testing.T) {
 
 func TestObserver(t *testing.T) {
 	{
-		labels := []core.KeyValue{key.String("O", "P")}
+		labels := []kv.KeyValue{kv.String("O", "P")}
 		mockSDK, meter := mockTest.NewMeter()
 		o := Must(meter).RegisterFloat64Observer("test.observer.float", func(result metric.Float64ObserverResult) {
 			result.Observe(42, labels...)
@@ -160,7 +159,7 @@ func TestObserver(t *testing.T) {
 		checkObserverBatch(t, labels, mockSDK, metric.Float64NumberKind, o.AsyncImpl())
 	}
 	{
-		labels := []core.KeyValue{}
+		labels := []kv.KeyValue{}
 		mockSDK, meter := mockTest.NewMeter()
 		o := Must(meter).RegisterInt64Observer("test.observer.int", func(result metric.Int64ObserverResult) {
 			result.Observe(42, labels...)
@@ -171,7 +170,7 @@ func TestObserver(t *testing.T) {
 	}
 }
 
-func checkBatches(t *testing.T, ctx context.Context, labels []core.KeyValue, mock *mockTest.MeterImpl, kind metric.NumberKind, instrument metric.InstrumentImpl) {
+func checkBatches(t *testing.T, ctx context.Context, labels []kv.KeyValue, mock *mockTest.MeterImpl, kind metric.NumberKind, instrument metric.InstrumentImpl) {
 	t.Helper()
 	if len(mock.MeasurementBatches) != 3 {
 		t.Errorf("Expected 3 recorded measurement batches, got %d", len(mock.MeasurementBatches))
@@ -211,7 +210,7 @@ func checkBatches(t *testing.T, ctx context.Context, labels []core.KeyValue, moc
 	}
 }
 
-func checkObserverBatch(t *testing.T, labels []core.KeyValue, mock *mockTest.MeterImpl, kind metric.NumberKind, observer metric.AsyncImpl) {
+func checkObserverBatch(t *testing.T, labels []kv.KeyValue, mock *mockTest.MeterImpl, kind metric.NumberKind, observer metric.AsyncImpl) {
 	t.Helper()
 	assert.Len(t, mock.MeasurementBatches, 1)
 	if len(mock.MeasurementBatches) < 1 {
@@ -250,14 +249,14 @@ type testWrappedMeter struct {
 
 var _ metric.MeterImpl = testWrappedMeter{}
 
-func (testWrappedMeter) RecordBatch(context.Context, []core.KeyValue, ...metric.Measurement) {
+func (testWrappedMeter) RecordBatch(context.Context, []kv.KeyValue, ...metric.Measurement) {
 }
 
 func (testWrappedMeter) NewSyncInstrument(_ metric.Descriptor) (metric.SyncImpl, error) {
 	return nil, nil
 }
 
-func (testWrappedMeter) NewAsyncInstrument(_ metric.Descriptor, _ func(func(metric.Number, []core.KeyValue))) (metric.AsyncImpl, error) {
+func (testWrappedMeter) NewAsyncInstrument(_ metric.Descriptor, _ func(func(metric.Number, []kv.KeyValue))) (metric.AsyncImpl, error) {
 	return nil, errors.New("Test wrap error")
 }
 
diff --git a/api/testharness/harness.go b/api/testharness/harness.go
index 834d94e4..f2192145 100644
--- a/api/testharness/harness.go
+++ b/api/testharness/harness.go
@@ -21,9 +21,10 @@ import (
 	"testing"
 	"time"
 
+	"go.opentelemetry.io/otel/api/kv"
+
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/key"
 	"go.opentelemetry.io/otel/api/trace"
 	"go.opentelemetry.io/otel/internal/matchers"
 )
@@ -329,7 +330,7 @@ func (h *Harness) testSpan(tracerFactory func() trace.Tracer) {
 			span.SetName("new name")
 		},
 		"#SetAttributes": func(span trace.Span) {
-			span.SetAttributes(key.String("key1", "value"), key.Int("key2", 123))
+			span.SetAttributes(kv.String("key1", "value"), kv.Int("key2", 123))
 		},
 	}
 	var mechanisms = map[string]func() trace.Span{
diff --git a/api/trace/always_off_sampler_test.go b/api/trace/always_off_sampler_test.go
index cc87af41..3ead3343 100644
--- a/api/trace/always_off_sampler_test.go
+++ b/api/trace/always_off_sampler_test.go
@@ -19,12 +19,12 @@ import (
 
 	"github.com/google/go-cmp/cmp"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 func TestNeverSamperShouldSample(t *testing.T) {
 	gotD := AlwaysOffSampler().ShouldSample(
-		SpanContext{}, false, ID{}, SpanID{}, "span", SpanKindClient, []core.KeyValue{}, []Link{})
+		SpanContext{}, false, ID{}, SpanID{}, "span", SpanKindClient, []kv.KeyValue{}, []Link{})
 	wantD := Decision{Sampled: false}
 	if diff := cmp.Diff(wantD, gotD); diff != "" {
 		t.Errorf("Decision: +got, -want%v", diff)
diff --git a/api/trace/always_on_sampler_test.go b/api/trace/always_on_sampler_test.go
index 88f83f36..03343319 100644
--- a/api/trace/always_on_sampler_test.go
+++ b/api/trace/always_on_sampler_test.go
@@ -19,12 +19,12 @@ import (
 
 	"github.com/google/go-cmp/cmp"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 func TestAlwaysOnSamplerShouldSample(t *testing.T) {
 	gotD := AlwaysOnSampler().ShouldSample(
-		SpanContext{}, false, ID{}, SpanID{}, "span", SpanKindClient, []core.KeyValue{}, []Link{})
+		SpanContext{}, false, ID{}, SpanID{}, "span", SpanKindClient, []kv.KeyValue{}, []Link{})
 	wantD := Decision{Sampled: true}
 	if diff := cmp.Diff(wantD, gotD); diff != "" {
 		t.Errorf("Decision: +got, -want%v", diff)
diff --git a/api/trace/context_test.go b/api/trace/context_test.go
index 1c014eeb..fd03d146 100644
--- a/api/trace/context_test.go
+++ b/api/trace/context_test.go
@@ -21,7 +21,7 @@ import (
 
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/trace"
 )
 
@@ -94,7 +94,7 @@ func (mockSpan) SetError(v bool) {
 }
 
 // SetAttributes does nothing.
-func (mockSpan) SetAttributes(attributes ...core.KeyValue) {
+func (mockSpan) SetAttributes(attributes ...kv.KeyValue) {
 }
 
 // SetAttribute does nothing.
@@ -115,9 +115,9 @@ func (mockSpan) Tracer() trace.Tracer {
 }
 
 // Event does nothing.
-func (mockSpan) AddEvent(ctx context.Context, name string, attrs ...core.KeyValue) {
+func (mockSpan) AddEvent(ctx context.Context, name string, attrs ...kv.KeyValue) {
 }
 
 // AddEventWithTimestamp does nothing.
-func (mockSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...core.KeyValue) {
+func (mockSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...kv.KeyValue) {
 }
diff --git a/api/trace/testtrace/event.go b/api/trace/testtrace/event.go
index 60d1e8c0..69e0e1db 100644
--- a/api/trace/testtrace/event.go
+++ b/api/trace/testtrace/event.go
@@ -17,12 +17,14 @@ package testtrace
 import (
 	"time"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
+
+	"go.opentelemetry.io/otel/api/kv/value"
 )
 
 // Event encapsulates the properties of calls to AddEvent or AddEventWithTimestamp.
 type Event struct {
 	Timestamp  time.Time
 	Name       string
-	Attributes map[core.Key]core.Value
+	Attributes map[kv.Key]value.Value
 }
diff --git a/api/trace/testtrace/span.go b/api/trace/testtrace/span.go
index a97805ae..9053bfff 100644
--- a/api/trace/testtrace/span.go
+++ b/api/trace/testtrace/span.go
@@ -21,16 +21,17 @@ import (
 	"sync"
 	"time"
 
+	"go.opentelemetry.io/otel/api/kv/value"
+
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/trace"
 )
 
 const (
-	errorTypeKey    = core.Key("error.type")
-	errorMessageKey = core.Key("error.message")
+	errorTypeKey    = kv.Key("error.type")
+	errorMessageKey = kv.Key("error.message")
 	errorEventName  = "error"
 )
 
@@ -47,9 +48,9 @@ type Span struct {
 	endTime       time.Time
 	statusCode    codes.Code
 	statusMessage string
-	attributes    map[core.Key]core.Value
+	attributes    map[kv.Key]value.Value
 	events        []Event
-	links         map[trace.SpanContext][]core.KeyValue
+	links         map[trace.SpanContext][]kv.KeyValue
 }
 
 func (s *Span) Tracer() trace.Tracer {
@@ -109,11 +110,11 @@ func (s *Span) RecordError(ctx context.Context, err error, opts ...trace.ErrorOp
 	)
 }
 
-func (s *Span) AddEvent(ctx context.Context, name string, attrs ...core.KeyValue) {
+func (s *Span) AddEvent(ctx context.Context, name string, attrs ...kv.KeyValue) {
 	s.AddEventWithTimestamp(ctx, time.Now(), name, attrs...)
 }
 
-func (s *Span) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...core.KeyValue) {
+func (s *Span) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...kv.KeyValue) {
 	s.lock.Lock()
 	defer s.lock.Unlock()
 
@@ -121,7 +122,7 @@ func (s *Span) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, n
 		return
 	}
 
-	attributes := make(map[core.Key]core.Value)
+	attributes := make(map[kv.Key]value.Value)
 
 	for _, attr := range attrs {
 		attributes[attr.Key] = attr.Value
@@ -165,7 +166,7 @@ func (s *Span) SetName(name string) {
 	s.name = name
 }
 
-func (s *Span) SetAttributes(attrs ...core.KeyValue) {
+func (s *Span) SetAttributes(attrs ...kv.KeyValue) {
 	s.lock.Lock()
 	defer s.lock.Unlock()
 
@@ -179,7 +180,7 @@ func (s *Span) SetAttributes(attrs ...core.KeyValue) {
 }
 
 func (s *Span) SetAttribute(k string, v interface{}) {
-	s.SetAttributes(key.Infer(k, v))
+	s.SetAttributes(kv.Infer(k, v))
 }
 
 // Name returns the name most recently set on the Span, either at or after creation time.
@@ -198,11 +199,11 @@ func (s *Span) ParentSpanID() trace.SpanID {
 // Attributes returns the attributes set on the Span, either at or after creation time.
 // If the same attribute key was set multiple times, the last call will be used.
 // Attributes cannot be changed after End has been called on the Span.
-func (s *Span) Attributes() map[core.Key]core.Value {
+func (s *Span) Attributes() map[kv.Key]value.Value {
 	s.lock.RLock()
 	defer s.lock.RUnlock()
 
-	attributes := make(map[core.Key]core.Value)
+	attributes := make(map[kv.Key]value.Value)
 
 	for k, v := range s.attributes {
 		attributes[k] = v
@@ -219,11 +220,11 @@ func (s *Span) Events() []Event {
 
 // Links returns the links set on the Span at creation time.
 // If multiple links for the same SpanContext were set, the last link will be used.
-func (s *Span) Links() map[trace.SpanContext][]core.KeyValue {
-	links := make(map[trace.SpanContext][]core.KeyValue)
+func (s *Span) Links() map[trace.SpanContext][]kv.KeyValue {
+	links := make(map[trace.SpanContext][]kv.KeyValue)
 
 	for sc, attributes := range s.links {
-		links[sc] = append([]core.KeyValue{}, attributes...)
+		links[sc] = append([]kv.KeyValue{}, attributes...)
 	}
 
 	return links
diff --git a/api/trace/testtrace/span_test.go b/api/trace/testtrace/span_test.go
index 455e4e4d..9b46bd6e 100644
--- a/api/trace/testtrace/span_test.go
+++ b/api/trace/testtrace/span_test.go
@@ -22,10 +22,11 @@ import (
 	"testing"
 	"time"
 
+	"go.opentelemetry.io/otel/api/kv/value"
+
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/trace"
 	"go.opentelemetry.io/otel/api/trace/testtrace"
 	"go.opentelemetry.io/otel/internal/matchers"
@@ -160,9 +161,9 @@ func TestSpan(t *testing.T) {
 				expectedEvents := []testtrace.Event{{
 					Timestamp: testTime,
 					Name:      "error",
-					Attributes: map[core.Key]core.Value{
-						core.Key("error.type"):    core.String(s.typ),
-						core.Key("error.message"): core.String(s.msg),
+					Attributes: map[kv.Key]value.Value{
+						kv.Key("error.type"):    value.String(s.typ),
+						kv.Key("error.message"): value.String(s.msg),
 					},
 				}}
 				e.Expect(subject.Events()).ToEqual(expectedEvents)
@@ -191,9 +192,9 @@ func TestSpan(t *testing.T) {
 			expectedEvents := []testtrace.Event{{
 				Timestamp: testTime,
 				Name:      "error",
-				Attributes: map[core.Key]core.Value{
-					core.Key("error.type"):    core.String("go.opentelemetry.io/otel/internal/testing.TestError"),
-					core.Key("error.message"): core.String(errMsg),
+				Attributes: map[kv.Key]value.Value{
+					kv.Key("error.type"):    value.String("go.opentelemetry.io/otel/internal/testing.TestError"),
+					kv.Key("error.message"): value.String(errMsg),
 				},
 			}}
 			e.Expect(subject.Events()).ToEqual(expectedEvents)
@@ -326,7 +327,7 @@ func TestSpan(t *testing.T) {
 			subject, ok := span.(*testtrace.Span)
 			e.Expect(ok).ToBeTrue()
 
-			e.Expect(subject.Attributes()).ToEqual(map[core.Key]core.Value{})
+			e.Expect(subject.Attributes()).ToEqual(map[kv.Key]value.Value{})
 		})
 
 		t.Run("returns the most recently set attributes", func(t *testing.T) {
@@ -340,9 +341,9 @@ func TestSpan(t *testing.T) {
 			subject, ok := span.(*testtrace.Span)
 			e.Expect(ok).ToBeTrue()
 
-			attr1 := key.String("key1", "value1")
-			attr2 := key.String("key2", "value2")
-			attr3 := key.String("key3", "value3")
+			attr1 := kv.String("key1", "value1")
+			attr2 := kv.String("key2", "value2")
+			attr3 := kv.String("key3", "value3")
 			unexpectedAttr := attr2.Key.String("unexpected")
 
 			subject.SetAttributes(attr1, unexpectedAttr, attr3)
@@ -366,7 +367,7 @@ func TestSpan(t *testing.T) {
 			subject, ok := span.(*testtrace.Span)
 			e.Expect(ok).ToBeTrue()
 
-			expectedAttr := key.String("key", "value")
+			expectedAttr := kv.String("key", "value")
 			subject.SetAttributes(expectedAttr)
 			subject.End()
 
@@ -396,7 +397,7 @@ func TestSpan(t *testing.T) {
 			go func() {
 				defer wg.Done()
 
-				subject.SetAttributes(key.String("key", "value"))
+				subject.SetAttributes(kv.String("key", "value"))
 			}()
 
 			go func() {
@@ -452,9 +453,9 @@ func TestSpan(t *testing.T) {
 			e.Expect(ok).ToBeTrue()
 
 			event1Name := "event1"
-			event1Attributes := []core.KeyValue{
-				key.String("event1Attr1", "foo"),
-				key.String("event1Attr2", "bar"),
+			event1Attributes := []kv.KeyValue{
+				kv.String("event1Attr1", "foo"),
+				kv.String("event1Attr2", "bar"),
 			}
 
 			event1Start := time.Now()
@@ -463,8 +464,8 @@ func TestSpan(t *testing.T) {
 
 			event2Timestamp := time.Now().AddDate(5, 0, 0)
 			event2Name := "event1"
-			event2Attributes := []core.KeyValue{
-				key.String("event2Attr", "abc"),
+			event2Attributes := []kv.KeyValue{
+				kv.String("event2Attr", "abc"),
 			}
 
 			subject.AddEventWithTimestamp(context.Background(), event2Timestamp, event2Name, event2Attributes...)
diff --git a/api/trace/testtrace/tracer.go b/api/trace/testtrace/tracer.go
index 49dfdd45..cbb1c883 100644
--- a/api/trace/testtrace/tracer.go
+++ b/api/trace/testtrace/tracer.go
@@ -19,7 +19,9 @@ import (
 	"sync"
 	"time"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv/value"
+
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/trace"
 
 	"go.opentelemetry.io/otel/internal/trace/parent"
@@ -80,8 +82,8 @@ func (t *Tracer) Start(ctx context.Context, name string, opts ...trace.StartOpti
 			SpanID:  spanID,
 		},
 		parentSpanID: parentSpanID,
-		attributes:   make(map[core.Key]core.Value),
-		links:        make(map[trace.SpanContext][]core.KeyValue),
+		attributes:   make(map[kv.Key]value.Value),
+		links:        make(map[trace.SpanContext][]kv.KeyValue),
 	}
 
 	span.SetName(name)
diff --git a/api/trace/testtrace/tracer_test.go b/api/trace/testtrace/tracer_test.go
index 8bf0a753..fff385e1 100644
--- a/api/trace/testtrace/tracer_test.go
+++ b/api/trace/testtrace/tracer_test.go
@@ -20,8 +20,7 @@ import (
 	"testing"
 	"time"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/testharness"
 	"go.opentelemetry.io/otel/api/trace"
 	"go.opentelemetry.io/otel/api/trace/testtrace"
@@ -61,8 +60,8 @@ func TestTracer(t *testing.T) {
 
 			e := matchers.NewExpecter(t)
 
-			attr1 := key.String("a", "1")
-			attr2 := key.String("b", "2")
+			attr1 := kv.String("a", "1")
+			attr2 := kv.String("b", "2")
 
 			subject := testtrace.NewTracer()
 			_, span := subject.Start(context.Background(), "test", trace.WithAttributes(attr1, attr2))
@@ -194,14 +193,14 @@ func TestTracer(t *testing.T) {
 			expectedLinks := []trace.Link{
 				{
 					SpanContext: parentSpanContext,
-					Attributes: []core.KeyValue{
-						key.String("ignored-on-demand", "current"),
+					Attributes: []kv.KeyValue{
+						kv.String("ignored-on-demand", "current"),
 					},
 				},
 				{
 					SpanContext: remoteParentSpanContext,
-					Attributes: []core.KeyValue{
-						key.String("ignored-on-demand", "remote"),
+					Attributes: []kv.KeyValue{
+						kv.String("ignored-on-demand", "remote"),
 					},
 				},
 			}
@@ -226,16 +225,16 @@ func TestTracer(t *testing.T) {
 			_, span := subject.Start(context.Background(), "link1")
 			link1 := trace.Link{
 				SpanContext: span.SpanContext(),
-				Attributes: []core.KeyValue{
-					key.String("a", "1"),
+				Attributes: []kv.KeyValue{
+					kv.String("a", "1"),
 				},
 			}
 
 			_, span = subject.Start(context.Background(), "link2")
 			link2 := trace.Link{
 				SpanContext: span.SpanContext(),
-				Attributes: []core.KeyValue{
-					key.String("b", "2"),
+				Attributes: []kv.KeyValue{
+					kv.String("b", "2"),
 				},
 			}
 
@@ -268,8 +267,8 @@ func TestTracer(t *testing.T) {
 
 			e := matchers.NewExpecter(t)
 
-			attr1 := key.String("a", "1")
-			attr2 := key.String("b", "2")
+			attr1 := kv.String("a", "1")
+			attr2 := kv.String("b", "2")
 
 			subject := testtrace.NewTracer()
 			var span trace.Span
diff --git a/bridge/opentracing/mix_test.go b/bridge/opentracing/mix_test.go
index f1f4dd44..4fb67e43 100644
--- a/bridge/opentracing/mix_test.go
+++ b/bridge/opentracing/mix_test.go
@@ -21,10 +21,9 @@ import (
 
 	ot "github.com/opentracing/opentracing-go"
 
-	otelcore "go.opentelemetry.io/otel/api/core"
 	otelcorrelation "go.opentelemetry.io/otel/api/correlation"
 	otelglobal "go.opentelemetry.io/otel/api/global"
-	otelkey "go.opentelemetry.io/otel/api/key"
+	otelcore "go.opentelemetry.io/otel/api/kv"
 	oteltrace "go.opentelemetry.io/otel/api/trace"
 
 	"go.opentelemetry.io/otel/bridge/opentracing/internal"
@@ -590,7 +589,7 @@ func (bio *baggageInteroperationTest) addAndRecordBaggage(t *testing.T, ctx cont
 	value := bio.baggageItems[idx].value
 
 	otSpan.SetBaggageItem(otKey, value)
-	ctx = otelcorrelation.NewContext(ctx, otelkey.String(otelKey, value))
+	ctx = otelcorrelation.NewContext(ctx, otelcore.String(otelKey, value))
 
 	otRecording := make(map[string]string)
 	otSpan.Context().ForeachBaggageItem(func(key, value string) bool {
diff --git a/exporters/metric/prometheus/prometheus_test.go b/exporters/metric/prometheus/prometheus_test.go
index b69ff4e5..3a0b8add 100644
--- a/exporters/metric/prometheus/prometheus_test.go
+++ b/exporters/metric/prometheus/prometheus_test.go
@@ -24,8 +24,7 @@ import (
 
 	"github.com/stretchr/testify/require"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 	"go.opentelemetry.io/otel/exporters/metric/prometheus"
 	"go.opentelemetry.io/otel/exporters/metric/test"
@@ -51,9 +50,9 @@ func TestPrometheusExporter(t *testing.T) {
 	histogramMeasure := metric.NewDescriptor(
 		"histogram_measure", metric.MeasureKind, metric.Float64NumberKind)
 
-	labels := []core.KeyValue{
-		key.New("A").String("B"),
-		key.New("C").String("D"),
+	labels := []kv.KeyValue{
+		kv.NewKey("A").String("B"),
+		kv.NewKey("C").String("D"),
 	}
 
 	checkpointSet.AddCounter(&counter, 15.3, labels...)
@@ -83,9 +82,9 @@ func TestPrometheusExporter(t *testing.T) {
 	expected = append(expected, `histogram_measure_count{A="B",C="D"} 4`)
 	expected = append(expected, `histogram_measure_sum{A="B",C="D"} 19.6`)
 
-	missingLabels := []core.KeyValue{
-		key.New("A").String("E"),
-		key.New("C").String(""),
+	missingLabels := []kv.KeyValue{
+		kv.NewKey("A").String("E"),
+		kv.NewKey("C").String(""),
 	}
 
 	checkpointSet.AddCounter(&counter, 12, missingLabels...)
diff --git a/exporters/metric/stdout/example_test.go b/exporters/metric/stdout/example_test.go
index 06e45790..f86d175e 100644
--- a/exporters/metric/stdout/example_test.go
+++ b/exporters/metric/stdout/example_test.go
@@ -19,8 +19,7 @@ import (
 	"log"
 	"time"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 	"go.opentelemetry.io/otel/exporters/metric/stdout"
 )
@@ -38,12 +37,12 @@ func ExampleNewExportPipeline() {
 
 	ctx := context.Background()
 
-	key := key.New("key")
+	key := kv.NewKey("key")
 	meter := pusher.Meter("example")
 
 	// Create and update a single counter:
 	counter := metric.Must(meter).NewInt64Counter("a.counter")
-	labels := []core.KeyValue{key.String("value")}
+	labels := []kv.KeyValue{key.String("value")}
 
 	counter.Add(ctx, 100, labels...)
 
diff --git a/exporters/metric/stdout/stdout_test.go b/exporters/metric/stdout/stdout_test.go
index 735dce18..a5f94df6 100644
--- a/exporters/metric/stdout/stdout_test.go
+++ b/exporters/metric/stdout/stdout_test.go
@@ -24,8 +24,7 @@ import (
 
 	"github.com/stretchr/testify/require"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 	"go.opentelemetry.io/otel/exporters/metric/stdout"
 	"go.opentelemetry.io/otel/exporters/metric/test"
@@ -149,7 +148,7 @@ func TestStdoutCounterFormat(t *testing.T) {
 	aggtest.CheckedUpdate(fix.t, cagg, metric.NewInt64Number(123), &desc)
 	cagg.Checkpoint(fix.ctx, &desc)
 
-	checkpointSet.Add(&desc, cagg, key.String("A", "B"), key.String("C", "D"))
+	checkpointSet.Add(&desc, cagg, kv.String("A", "B"), kv.String("C", "D"))
 
 	fix.Export(checkpointSet)
 
@@ -166,7 +165,7 @@ func TestStdoutLastValueFormat(t *testing.T) {
 	aggtest.CheckedUpdate(fix.t, lvagg, metric.NewFloat64Number(123.456), &desc)
 	lvagg.Checkpoint(fix.ctx, &desc)
 
-	checkpointSet.Add(&desc, lvagg, key.String("A", "B"), key.String("C", "D"))
+	checkpointSet.Add(&desc, lvagg, kv.String("A", "B"), kv.String("C", "D"))
 
 	fix.Export(checkpointSet)
 
@@ -184,7 +183,7 @@ func TestStdoutMinMaxSumCount(t *testing.T) {
 	aggtest.CheckedUpdate(fix.t, magg, metric.NewFloat64Number(876.543), &desc)
 	magg.Checkpoint(fix.ctx, &desc)
 
-	checkpointSet.Add(&desc, magg, key.String("A", "B"), key.String("C", "D"))
+	checkpointSet.Add(&desc, magg, kv.String("A", "B"), kv.String("C", "D"))
 
 	fix.Export(checkpointSet)
 
@@ -207,7 +206,7 @@ func TestStdoutMeasureFormat(t *testing.T) {
 
 	magg.Checkpoint(fix.ctx, &desc)
 
-	checkpointSet.Add(&desc, magg, key.String("A", "B"), key.String("C", "D"))
+	checkpointSet.Add(&desc, magg, kv.String("A", "B"), kv.String("C", "D"))
 
 	fix.Export(checkpointSet)
 
@@ -273,7 +272,7 @@ func TestStdoutLastValueNotSet(t *testing.T) {
 	lvagg := lastvalue.New()
 	lvagg.Checkpoint(fix.ctx, &desc)
 
-	checkpointSet.Add(&desc, lvagg, key.String("A", "B"), key.String("C", "D"))
+	checkpointSet.Add(&desc, lvagg, kv.String("A", "B"), kv.String("C", "D"))
 
 	fix.Export(checkpointSet)
 
@@ -284,9 +283,9 @@ func TestStdoutResource(t *testing.T) {
 	type testCase struct {
 		expect string
 		res    *resource.Resource
-		attrs  []core.KeyValue
+		attrs  []kv.KeyValue
 	}
-	newCase := func(expect string, res *resource.Resource, attrs ...core.KeyValue) testCase {
+	newCase := func(expect string, res *resource.Resource, attrs ...kv.KeyValue) testCase {
 		return testCase{
 			expect: expect,
 			res:    res,
@@ -295,23 +294,23 @@ func TestStdoutResource(t *testing.T) {
 	}
 	testCases := []testCase{
 		newCase("R1=V1,R2=V2,A=B,C=D",
-			resource.New(key.String("R1", "V1"), key.String("R2", "V2")),
-			key.String("A", "B"),
-			key.String("C", "D")),
+			resource.New(kv.String("R1", "V1"), kv.String("R2", "V2")),
+			kv.String("A", "B"),
+			kv.String("C", "D")),
 		newCase("R1=V1,R2=V2",
-			resource.New(key.String("R1", "V1"), key.String("R2", "V2")),
+			resource.New(kv.String("R1", "V1"), kv.String("R2", "V2")),
 		),
 		newCase("A=B,C=D",
 			nil,
-			key.String("A", "B"),
-			key.String("C", "D"),
+			kv.String("A", "B"),
+			kv.String("C", "D"),
 		),
 		// We explicitly do not de-duplicate between resources
 		// and metric labels in this exporter.
 		newCase("R1=V1,R2=V2,R1=V3,R2=V4",
-			resource.New(key.String("R1", "V1"), key.String("R2", "V2")),
-			key.String("R1", "V3"),
-			key.String("R2", "V4")),
+			resource.New(kv.String("R1", "V1"), kv.String("R2", "V2")),
+			kv.String("R1", "V3"),
+			kv.String("R2", "V4")),
 	}
 
 	for _, tc := range testCases {
diff --git a/exporters/metric/test/test.go b/exporters/metric/test/test.go
index a3ff395e..a7dca90d 100644
--- a/exporters/metric/test/test.go
+++ b/exporters/metric/test/test.go
@@ -18,7 +18,7 @@ import (
 	"context"
 	"errors"
 
-	"go.opentelemetry.io/otel/api/core"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/label"
 	"go.opentelemetry.io/otel/api/metric"
 	export "go.opentelemetry.io/otel/sdk/export/metric"
@@ -56,7 +56,7 @@ func (p *CheckpointSet) Reset() {
 //
 // If there is an existing record with the same descriptor and labels,
 // the stored aggregator will be returned and should be merged.
-func (p *CheckpointSet) Add(desc *metric.Descriptor, newAgg export.Aggregator, labels ...core.KeyValue) (agg export.Aggregator, added bool) {
+func (p *CheckpointSet) Add(desc *metric.Descriptor, newAgg export.Aggregator, labels ...kv.KeyValue) (agg export.Aggregator, added bool) {
 	elabels := label.NewSet(labels...)
 
 	key := mapkey{
@@ -80,23 +80,23 @@ func createNumber(desc *metric.Descriptor, v float64) metric.Number {
 	return metric.NewInt64Number(int64(v))
 }
 
-func (p *CheckpointSet) AddLastValue(desc *metric.Descriptor, v float64, labels ...core.KeyValue) {
+func (p *CheckpointSet) AddLastValue(desc *metric.Descriptor, v float64, labels ...kv.KeyValue) {
 	p.updateAggregator(desc, lastvalue.New(), v, labels...)
 }
 
-func (p *CheckpointSet) AddCounter(desc *metric.Descriptor, v float64, labels ...core.KeyValue) {
+func (p *CheckpointSet) AddCounter(desc *metric.Descriptor, v float64, labels ...kv.KeyValue) {
 	p.updateAggregator(desc, sum.New(), v, labels...)
 }
 
-func (p *CheckpointSet) AddMeasure(desc *metric.Descriptor, v float64, labels ...core.KeyValue) {
+func (p *CheckpointSet) AddMeasure(desc *metric.Descriptor, v float64, labels ...kv.KeyValue) {
 	p.updateAggregator(desc, array.New(), v, labels...)
 }
 
-func (p *CheckpointSet) AddHistogramMeasure(desc *metric.Descriptor, boundaries []metric.Number, v float64, labels ...core.KeyValue) {
+func (p *CheckpointSet) AddHistogramMeasure(desc *metric.Descriptor, boundaries []metric.Number, v float64, labels ...kv.KeyValue) {
 	p.updateAggregator(desc, histogram.New(desc, boundaries), v, labels...)
 }
 
-func (p *CheckpointSet) updateAggregator(desc *metric.Descriptor, newAgg export.Aggregator, v float64, labels ...core.KeyValue) {
+func (p *CheckpointSet) updateAggregator(desc *metric.Descriptor, newAgg export.Aggregator, v float64, labels ...kv.KeyValue) {
 	ctx := context.Background()
 	// Updates and checkpoint the new aggregator
 	_ = newAgg.Update(ctx, createNumber(desc, v), desc)
diff --git a/exporters/otlp/internal/transform/attribute_test.go b/exporters/otlp/internal/transform/attribute_test.go
index 825cbf3c..e6dea24d 100644
--- a/exporters/otlp/internal/transform/attribute_test.go
+++ b/exporters/otlp/internal/transform/attribute_test.go
@@ -20,28 +20,27 @@ import (
 	commonpb "github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1"
 	"github.com/stretchr/testify/assert"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 )
 
 func TestAttributes(t *testing.T) {
 	for _, test := range []struct {
-		attrs    []core.KeyValue
+		attrs    []kv.KeyValue
 		expected []*commonpb.AttributeKeyValue
 	}{
 		{nil, nil},
 		{
-			[]core.KeyValue{
-				key.Int("int to int", 123),
-				key.Uint("uint to int", 1234),
-				key.Int32("int32 to int", 12345),
-				key.Uint32("uint32 to int", 123456),
-				key.Int64("int64 to int64", 1234567),
-				key.Uint64("uint64 to int64", 12345678),
-				key.Float32("float32 to double", 3.14),
-				key.Float32("float64 to double", 1.61),
-				key.String("string to string", "string"),
-				key.Bool("bool to bool", true),
+			[]kv.KeyValue{
+				kv.Int("int to int", 123),
+				kv.Uint("uint to int", 1234),
+				kv.Int32("int32 to int", 12345),
+				kv.Uint32("uint32 to int", 123456),
+				kv.Int64("int64 to int64", 1234567),
+				kv.Uint64("uint64 to int64", 12345678),
+				kv.Float32("float32 to double", 3.14),
+				kv.Float32("float64 to double", 1.61),
+				kv.String("string to string", "string"),
+				kv.Bool("bool to bool", true),
 			},
 			[]*commonpb.AttributeKeyValue{
 				{
diff --git a/exporters/otlp/internal/transform/metric_test.go b/exporters/otlp/internal/transform/metric_test.go
index a632cf96..57e0388a 100644
--- a/exporters/otlp/internal/transform/metric_test.go
+++ b/exporters/otlp/internal/transform/metric_test.go
@@ -23,8 +23,7 @@ import (
 	metricpb "github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1"
 	"github.com/stretchr/testify/assert"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/label"
 	"go.opentelemetry.io/otel/api/metric"
 	"go.opentelemetry.io/otel/api/unit"
@@ -35,7 +34,7 @@ import (
 
 func TestStringKeyValues(t *testing.T) {
 	tests := []struct {
-		kvs      []core.KeyValue
+		kvs      []kv.KeyValue
 		expected []*commonpb.StringKeyValue
 	}{
 		{
@@ -43,21 +42,21 @@ func TestStringKeyValues(t *testing.T) {
 			nil,
 		},
 		{
-			[]core.KeyValue{},
+			[]kv.KeyValue{},
 			nil,
 		},
 		{
-			[]core.KeyValue{
-				key.Bool("true", true),
-				key.Int64("one", 1),
-				key.Uint64("two", 2),
-				key.Float64("three", 3),
-				key.Int32("four", 4),
-				key.Uint32("five", 5),
-				key.Float32("six", 6),
-				key.Int("seven", 7),
-				key.Uint("eight", 8),
-				key.String("the", "final word"),
+			[]kv.KeyValue{
+				kv.Bool("true", true),
+				kv.Int64("one", 1),
+				kv.Uint64("two", 2),
+				kv.Float64("three", 3),
+				kv.Int32("four", 4),
+				kv.Uint32("five", 5),
+				kv.Float32("six", 6),
+				kv.Int("seven", 7),
+				kv.Uint("eight", 8),
+				kv.String("the", "final word"),
 			},
 			[]*commonpb.StringKeyValue{
 				{Key: "eight", Value: "8"},
@@ -107,7 +106,7 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) {
 		description string
 		unit        unit.Unit
 		numberKind  metric.NumberKind
-		labels      []core.KeyValue
+		labels      []kv.KeyValue
 		expected    *metricpb.MetricDescriptor
 	}{
 		{
@@ -116,7 +115,7 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) {
 			"test-a-description",
 			unit.Dimensionless,
 			metric.Int64NumberKind,
-			[]core.KeyValue{},
+			[]kv.KeyValue{},
 			&metricpb.MetricDescriptor{
 				Name:        "mmsc-test-a",
 				Description: "test-a-description",
@@ -131,7 +130,7 @@ func TestMinMaxSumCountMetricDescriptor(t *testing.T) {
 			"test-b-description",
 			unit.Bytes,
 			metric.Float64NumberKind, // This shouldn't change anything.
-			[]core.KeyValue{key.String("A", "1")},
+			[]kv.KeyValue{kv.String("A", "1")},
 			&metricpb.MetricDescriptor{
 				Name:        "mmsc-test-b",
 				Description: "test-b-description",
@@ -209,7 +208,7 @@ func TestSumMetricDescriptor(t *testing.T) {
 		description string
 		unit        unit.Unit
 		numberKind  metric.NumberKind
-		labels      []core.KeyValue
+		labels      []kv.KeyValue
 		expected    *metricpb.MetricDescriptor
 	}{
 		{
@@ -218,7 +217,7 @@ func TestSumMetricDescriptor(t *testing.T) {
 			"test-a-description",
 			unit.Dimensionless,
 			metric.Int64NumberKind,
-			[]core.KeyValue{},
+			[]kv.KeyValue{},
 			&metricpb.MetricDescriptor{
 				Name:        "sum-test-a",
 				Description: "test-a-description",
@@ -233,7 +232,7 @@ func TestSumMetricDescriptor(t *testing.T) {
 			"test-b-description",
 			unit.Milliseconds,
 			metric.Float64NumberKind,
-			[]core.KeyValue{key.String("A", "1")},
+			[]kv.KeyValue{kv.String("A", "1")},
 			&metricpb.MetricDescriptor{
 				Name:        "sum-test-b",
 				Description: "test-b-description",
diff --git a/exporters/otlp/internal/transform/resource_test.go b/exporters/otlp/internal/transform/resource_test.go
index 7dcf1351..34c1d52c 100644
--- a/exporters/otlp/internal/transform/resource_test.go
+++ b/exporters/otlp/internal/transform/resource_test.go
@@ -19,8 +19,7 @@ import (
 
 	"github.com/stretchr/testify/assert"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/sdk/resource"
 )
 
@@ -39,7 +38,7 @@ func TestEmptyResource(t *testing.T) {
  */
 
 func TestResourceAttributes(t *testing.T) {
-	attrs := []core.KeyValue{key.Int("one", 1), key.Int("two", 2)}
+	attrs := []kv.KeyValue{kv.Int("one", 1), kv.Int("two", 2)}
 
 	got := Resource(resource.New(attrs...)).GetAttributes()
 	if !assert.Len(t, attrs, 2) {
diff --git a/exporters/otlp/internal/transform/span_test.go b/exporters/otlp/internal/transform/span_test.go
index 90ed5d2f..1fb6a987 100644
--- a/exporters/otlp/internal/transform/span_test.go
+++ b/exporters/otlp/internal/transform/span_test.go
@@ -25,8 +25,7 @@ import (
 	"github.com/stretchr/testify/assert"
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	apitrace "go.opentelemetry.io/otel/api/trace"
 	export "go.opentelemetry.io/otel/sdk/export/trace"
 	"go.opentelemetry.io/otel/sdk/resource"
@@ -75,12 +74,12 @@ func TestEmptySpanEvent(t *testing.T) {
 }
 
 func TestSpanEvent(t *testing.T) {
-	attrs := []core.KeyValue{key.Int("one", 1), key.Int("two", 2)}
+	attrs := []kv.KeyValue{kv.Int("one", 1), kv.Int("two", 2)}
 	now := time.Now()
 	got := spanEvents([]export.Event{
 		{
 			Name:       "test 1",
-			Attributes: []core.KeyValue{},
+			Attributes: []kv.KeyValue{},
 			Time:       now,
 		},
 		{
@@ -119,7 +118,7 @@ func TestEmptyLinks(t *testing.T) {
 }
 
 func TestLinks(t *testing.T) {
-	attrs := []core.KeyValue{key.Int("one", 1), key.Int("two", 2)}
+	attrs := []kv.KeyValue{kv.Int("one", 1), kv.Int("two", 2)}
 	l := []apitrace.Link{
 		{},
 		{
@@ -281,13 +280,13 @@ func TestSpanData(t *testing.T) {
 		EndTime:      endTime,
 		MessageEvents: []export.Event{
 			{Time: startTime,
-				Attributes: []core.KeyValue{
-					key.Uint64("CompressedByteSize", 512),
+				Attributes: []kv.KeyValue{
+					kv.Uint64("CompressedByteSize", 512),
 				},
 			},
 			{Time: endTime,
-				Attributes: []core.KeyValue{
-					key.String("MessageEventType", "Recv"),
+				Attributes: []kv.KeyValue{
+					kv.String("MessageEventType", "Recv"),
 				},
 			},
 		},
@@ -298,8 +297,8 @@ func TestSpanData(t *testing.T) {
 					SpanID:     apitrace.SpanID{0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7},
 					TraceFlags: 0,
 				},
-				Attributes: []core.KeyValue{
-					key.String("LinkType", "Parent"),
+				Attributes: []kv.KeyValue{
+					kv.String("LinkType", "Parent"),
 				},
 			},
 			{
@@ -308,21 +307,21 @@ func TestSpanData(t *testing.T) {
 					SpanID:     apitrace.SpanID{0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7},
 					TraceFlags: 0,
 				},
-				Attributes: []core.KeyValue{
-					key.String("LinkType", "Child"),
+				Attributes: []kv.KeyValue{
+					kv.String("LinkType", "Child"),
 				},
 			},
 		},
 		StatusCode:      codes.Internal,
 		StatusMessage:   "utterly unrecognized",
 		HasRemoteParent: true,
-		Attributes: []core.KeyValue{
-			key.Int64("timeout_ns", 12e9),
+		Attributes: []kv.KeyValue{
+			kv.Int64("timeout_ns", 12e9),
 		},
 		DroppedAttributeCount:    1,
 		DroppedMessageEventCount: 2,
 		DroppedLinkCount:         3,
-		Resource:                 resource.New(key.String("rk1", "rv1"), key.Int64("rk2", 5)),
+		Resource:                 resource.New(kv.String("rk1", "rv1"), kv.Int64("rk2", 5)),
 	}
 
 	// Not checking resource as the underlying map of our Resource makes
diff --git a/exporters/otlp/otlp_integration_test.go b/exporters/otlp/otlp_integration_test.go
index b5814b84..79121a29 100644
--- a/exporters/otlp/otlp_integration_test.go
+++ b/exporters/otlp/otlp_integration_test.go
@@ -26,8 +26,7 @@ import (
 
 	metricpb "github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 	metricapi "go.opentelemetry.io/otel/api/metric"
 	"go.opentelemetry.io/otel/exporters/otlp"
@@ -87,13 +86,13 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption)
 		),
 	}
 	tp1, err := sdktrace.NewProvider(append(pOpts,
-		sdktrace.WithResourceAttributes(key.String("rk1", "rv11)"),
-			key.Int64("rk2", 5)))...)
+		sdktrace.WithResourceAttributes(kv.String("rk1", "rv11)"),
+			kv.Int64("rk2", 5)))...)
 	assert.NoError(t, err)
 
 	tp2, err := sdktrace.NewProvider(append(pOpts,
-		sdktrace.WithResourceAttributes(key.String("rk1", "rv12)"),
-			key.Float32("rk3", 6.5)))...)
+		sdktrace.WithResourceAttributes(kv.String("rk1", "rv12)"),
+			kv.Float32("rk3", 6.5)))...)
 	assert.NoError(t, err)
 
 	tr1 := tp1.Tracer("test-tracer1")
@@ -102,11 +101,11 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption)
 	m := 4
 	for i := 0; i < m; i++ {
 		_, span := tr1.Start(context.Background(), "AlwaysSample")
-		span.SetAttributes(key.Int64("i", int64(i)))
+		span.SetAttributes(kv.Int64("i", int64(i)))
 		span.End()
 
 		_, span = tr2.Start(context.Background(), "AlwaysSample")
-		span.SetAttributes(key.Int64("i", int64(i)))
+		span.SetAttributes(kv.Int64("i", int64(i)))
 		span.End()
 	}
 
@@ -117,7 +116,7 @@ func newExporterEndToEndTest(t *testing.T, additionalOpts []otlp.ExporterOption)
 
 	ctx := context.Background()
 	meter := pusher.Meter("test-meter")
-	labels := []core.KeyValue{key.Bool("test", true)}
+	labels := []kv.KeyValue{kv.Bool("test", true)}
 
 	type data struct {
 		iKind metric.Kind
diff --git a/exporters/otlp/otlp_metric_test.go b/exporters/otlp/otlp_metric_test.go
index 4b8e8d81..0471d0ad 100644
--- a/exporters/otlp/otlp_metric_test.go
+++ b/exporters/otlp/otlp_metric_test.go
@@ -25,8 +25,7 @@ import (
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/label"
 	"go.opentelemetry.io/otel/api/metric"
 	metricsdk "go.opentelemetry.io/otel/sdk/export/metric"
@@ -79,15 +78,15 @@ type record struct {
 	nKind    metric.NumberKind
 	resource *resource.Resource
 	opts     []metric.Option
-	labels   []core.KeyValue
+	labels   []kv.KeyValue
 }
 
 var (
-	baseKeyValues = []core.KeyValue{key.String("host", "test.com")}
-	cpuKey        = core.Key("CPU")
+	baseKeyValues = []kv.KeyValue{kv.String("host", "test.com")}
+	cpuKey        = kv.Key("CPU")
 
-	testInstA = resource.New(key.String("instance", "tester-a"))
-	testInstB = resource.New(key.String("instance", "tester-b"))
+	testInstA = resource.New(kv.String("instance", "tester-a"))
+	testInstB = resource.New(kv.String("instance", "tester-b"))
 
 	cpu1MD = &metricpb.MetricDescriptor{
 		Name: "int64-count",
@@ -714,7 +713,7 @@ func TestEmptyMetricExport(t *testing.T) {
 	exp.metricExporter = msc
 	exp.started = true
 
-	resource := resource.New(key.String("R", "S"))
+	resource := resource.New(kv.String("R", "S"))
 
 	for _, test := range []struct {
 		records []metricsdk.Record
diff --git a/exporters/otlp/otlp_span_test.go b/exporters/otlp/otlp_span_test.go
index 22e1ba71..1e63d21d 100644
--- a/exporters/otlp/otlp_span_test.go
+++ b/exporters/otlp/otlp_span_test.go
@@ -27,8 +27,7 @@ import (
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	apitrace "go.opentelemetry.io/otel/api/trace"
 	tracesdk "go.opentelemetry.io/otel/sdk/export/trace"
 	"go.opentelemetry.io/otel/sdk/resource"
@@ -90,13 +89,13 @@ func TestExportSpans(t *testing.T) {
 					Name:      "parent process",
 					StartTime: startTime,
 					EndTime:   endTime,
-					Attributes: []core.KeyValue{
-						key.String("user", "alice"),
-						key.Bool("authenticated", true),
+					Attributes: []kv.KeyValue{
+						kv.String("user", "alice"),
+						kv.Bool("authenticated", true),
 					},
 					StatusCode:    codes.OK,
 					StatusMessage: "Ok",
-					Resource:      resource.New(key.String("instance", "tester-a")),
+					Resource:      resource.New(kv.String("instance", "tester-a")),
 				},
 				{
 					SpanContext: apitrace.SpanContext{
@@ -109,13 +108,13 @@ func TestExportSpans(t *testing.T) {
 					Name:         "internal process",
 					StartTime:    startTime,
 					EndTime:      endTime,
-					Attributes: []core.KeyValue{
-						key.String("user", "alice"),
-						key.Bool("authenticated", true),
+					Attributes: []kv.KeyValue{
+						kv.String("user", "alice"),
+						kv.Bool("authenticated", true),
 					},
 					StatusCode:    codes.OK,
 					StatusMessage: "Ok",
-					Resource:      resource.New(key.String("instance", "tester-a")),
+					Resource:      resource.New(kv.String("instance", "tester-a")),
 				},
 				{
 					SpanContext: apitrace.SpanContext{
@@ -127,13 +126,13 @@ func TestExportSpans(t *testing.T) {
 					Name:      "parent process",
 					StartTime: startTime,
 					EndTime:   endTime,
-					Attributes: []core.KeyValue{
-						key.String("user", "bob"),
-						key.Bool("authenticated", false),
+					Attributes: []kv.KeyValue{
+						kv.String("user", "bob"),
+						kv.Bool("authenticated", false),
 					},
 					StatusCode:    codes.Unauthenticated,
 					StatusMessage: "Unauthenticated",
-					Resource:      resource.New(key.String("instance", "tester-b")),
+					Resource:      resource.New(kv.String("instance", "tester-b")),
 				},
 			},
 			[]tracepb.ResourceSpans{
diff --git a/exporters/trace/jaeger/jaeger_test.go b/exporters/trace/jaeger/jaeger_test.go
index bb234d8e..eca52408 100644
--- a/exporters/trace/jaeger/jaeger_test.go
+++ b/exporters/trace/jaeger/jaeger_test.go
@@ -25,9 +25,8 @@ import (
 	"github.com/stretchr/testify/assert"
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/global"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	apitrace "go.opentelemetry.io/otel/api/trace"
 	gen "go.opentelemetry.io/otel/exporters/trace/jaeger/internal/gen-go/jaeger"
 	export "go.opentelemetry.io/otel/sdk/export/trace"
@@ -94,8 +93,8 @@ func TestNewRawExporter(t *testing.T) {
 		WithCollectorEndpoint(collectorEndpoint),
 		WithProcess(Process{
 			ServiceName: serviceName,
-			Tags: []core.KeyValue{
-				key.String(tagKey, tagVal),
+			Tags: []kv.KeyValue{
+				kv.String(tagKey, tagVal),
 			},
 		}),
 	)
@@ -141,8 +140,8 @@ func TestExporter_ExportSpan(t *testing.T) {
 		withTestCollectorEndpoint(),
 		WithProcess(Process{
 			ServiceName: serviceName,
-			Tags: []core.KeyValue{
-				key.String(tagKey, tagVal),
+			Tags: []kv.KeyValue{
+				kv.String(tagKey, tagVal),
 			},
 		}),
 	)
@@ -230,19 +229,19 @@ func Test_spanDataToThrift(t *testing.T) {
 						},
 					},
 				},
-				Attributes: []core.KeyValue{
-					key.String("key", keyValue),
-					key.Float64("double", doubleValue),
+				Attributes: []kv.KeyValue{
+					kv.String("key", keyValue),
+					kv.Float64("double", doubleValue),
 					// Jaeger doesn't handle Uint tags, this should be ignored.
-					key.Uint64("ignored", 123),
+					kv.Uint64("ignored", 123),
 				},
 				MessageEvents: []export.Event{
-					{Name: eventNameValue, Attributes: []core.KeyValue{key.String("k1", keyValue)}, Time: now},
+					{Name: eventNameValue, Attributes: []kv.KeyValue{kv.String("k1", keyValue)}, Time: now},
 				},
 				StatusCode:    codes.Unknown,
 				StatusMessage: statusMessage,
 				SpanKind:      apitrace.SpanKindClient,
-				Resource:      resource.New(key.String("rk1", rv1), key.Int64("rk2", rv2)),
+				Resource:      resource.New(kv.String("rk1", rv1), kv.Int64("rk2", rv2)),
 			},
 			want: &gen.Span{
 				TraceIdLow:    651345242494996240,
diff --git a/exporters/trace/stdout/stdout_test.go b/exporters/trace/stdout/stdout_test.go
index f95edf01..91d5c74d 100644
--- a/exporters/trace/stdout/stdout_test.go
+++ b/exporters/trace/stdout/stdout_test.go
@@ -23,8 +23,7 @@ import (
 
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/trace"
 	export "go.opentelemetry.io/otel/sdk/export/trace"
 	"go.opentelemetry.io/otel/sdk/resource"
@@ -44,7 +43,7 @@ func TestExporter_ExportSpan(t *testing.T) {
 	spanID, _ := trace.SpanIDFromHex("0102030405060708")
 	keyValue := "value"
 	doubleValue := 123.456
-	resource := resource.New(key.String("rk1", "rv11"))
+	resource := resource.New(kv.String("rk1", "rv11"))
 
 	testSpan := &export.SpanData{
 		SpanContext: trace.SpanContext{
@@ -54,13 +53,13 @@ func TestExporter_ExportSpan(t *testing.T) {
 		Name:      "/foo",
 		StartTime: now,
 		EndTime:   now,
-		Attributes: []core.KeyValue{
-			key.String("key", keyValue),
-			key.Float64("double", doubleValue),
+		Attributes: []kv.KeyValue{
+			kv.String("key", keyValue),
+			kv.Float64("double", doubleValue),
 		},
 		MessageEvents: []export.Event{
-			{Name: "foo", Attributes: []core.KeyValue{key.String("key", keyValue)}, Time: now},
-			{Name: "bar", Attributes: []core.KeyValue{key.Float64("double", doubleValue)}, Time: now},
+			{Name: "foo", Attributes: []kv.KeyValue{kv.String("key", keyValue)}, Time: now},
+			{Name: "bar", Attributes: []kv.KeyValue{kv.Float64("double", doubleValue)}, Time: now},
 		},
 		SpanKind:      trace.SpanKindInternal,
 		StatusCode:    codes.Unknown,
diff --git a/exporters/trace/zipkin/model_test.go b/exporters/trace/zipkin/model_test.go
index 64f01fbe..87613033 100644
--- a/exporters/trace/zipkin/model_test.go
+++ b/exporters/trace/zipkin/model_test.go
@@ -22,8 +22,7 @@ import (
 	"github.com/stretchr/testify/require"
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/trace"
 	export "go.opentelemetry.io/otel/sdk/export/trace"
 )
@@ -41,16 +40,16 @@ func TestModelConversion(t *testing.T) {
 			Name:         "foo",
 			StartTime:    time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
 			EndTime:      time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
-			Attributes: []core.KeyValue{
-				key.Uint64("attr1", 42),
-				key.String("attr2", "bar"),
+			Attributes: []kv.KeyValue{
+				kv.Uint64("attr1", 42),
+				kv.String("attr2", "bar"),
 			},
 			MessageEvents: []export.Event{
 				{
 					Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
 					Name: "ev1",
-					Attributes: []core.KeyValue{
-						key.Uint64("eventattr1", 123),
+					Attributes: []kv.KeyValue{
+						kv.Uint64("eventattr1", 123),
 					},
 				},
 				{
@@ -74,16 +73,16 @@ func TestModelConversion(t *testing.T) {
 			Name:         "foo",
 			StartTime:    time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
 			EndTime:      time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
-			Attributes: []core.KeyValue{
-				key.Uint64("attr1", 42),
-				key.String("attr2", "bar"),
+			Attributes: []kv.KeyValue{
+				kv.Uint64("attr1", 42),
+				kv.String("attr2", "bar"),
 			},
 			MessageEvents: []export.Event{
 				{
 					Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
 					Name: "ev1",
-					Attributes: []core.KeyValue{
-						key.Uint64("eventattr1", 123),
+					Attributes: []kv.KeyValue{
+						kv.Uint64("eventattr1", 123),
 					},
 				},
 				{
@@ -106,16 +105,16 @@ func TestModelConversion(t *testing.T) {
 			Name:         "foo",
 			StartTime:    time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
 			EndTime:      time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
-			Attributes: []core.KeyValue{
-				key.Uint64("attr1", 42),
-				key.String("attr2", "bar"),
+			Attributes: []kv.KeyValue{
+				kv.Uint64("attr1", 42),
+				kv.String("attr2", "bar"),
 			},
 			MessageEvents: []export.Event{
 				{
 					Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
 					Name: "ev1",
-					Attributes: []core.KeyValue{
-						key.Uint64("eventattr1", 123),
+					Attributes: []kv.KeyValue{
+						kv.Uint64("eventattr1", 123),
 					},
 				},
 				{
@@ -138,16 +137,16 @@ func TestModelConversion(t *testing.T) {
 			Name:         "foo",
 			StartTime:    time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
 			EndTime:      time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
-			Attributes: []core.KeyValue{
-				key.Uint64("attr1", 42),
-				key.String("attr2", "bar"),
+			Attributes: []kv.KeyValue{
+				kv.Uint64("attr1", 42),
+				kv.String("attr2", "bar"),
 			},
 			MessageEvents: []export.Event{
 				{
 					Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
 					Name: "ev1",
-					Attributes: []core.KeyValue{
-						key.Uint64("eventattr1", 123),
+					Attributes: []kv.KeyValue{
+						kv.Uint64("eventattr1", 123),
 					},
 				},
 				{
@@ -170,16 +169,16 @@ func TestModelConversion(t *testing.T) {
 			Name:         "foo",
 			StartTime:    time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
 			EndTime:      time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
-			Attributes: []core.KeyValue{
-				key.Uint64("attr1", 42),
-				key.String("attr2", "bar"),
+			Attributes: []kv.KeyValue{
+				kv.Uint64("attr1", 42),
+				kv.String("attr2", "bar"),
 			},
 			MessageEvents: []export.Event{
 				{
 					Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
 					Name: "ev1",
-					Attributes: []core.KeyValue{
-						key.Uint64("eventattr1", 123),
+					Attributes: []kv.KeyValue{
+						kv.Uint64("eventattr1", 123),
 					},
 				},
 				{
@@ -202,16 +201,16 @@ func TestModelConversion(t *testing.T) {
 			Name:         "foo",
 			StartTime:    time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
 			EndTime:      time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
-			Attributes: []core.KeyValue{
-				key.Uint64("attr1", 42),
-				key.String("attr2", "bar"),
+			Attributes: []kv.KeyValue{
+				kv.Uint64("attr1", 42),
+				kv.String("attr2", "bar"),
 			},
 			MessageEvents: []export.Event{
 				{
 					Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
 					Name: "ev1",
-					Attributes: []core.KeyValue{
-						key.Uint64("eventattr1", 123),
+					Attributes: []kv.KeyValue{
+						kv.Uint64("eventattr1", 123),
 					},
 				},
 				{
@@ -234,16 +233,16 @@ func TestModelConversion(t *testing.T) {
 			Name:         "foo",
 			StartTime:    time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
 			EndTime:      time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
-			Attributes: []core.KeyValue{
-				key.Uint64("attr1", 42),
-				key.String("attr2", "bar"),
+			Attributes: []kv.KeyValue{
+				kv.Uint64("attr1", 42),
+				kv.String("attr2", "bar"),
 			},
 			MessageEvents: []export.Event{
 				{
 					Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
 					Name: "ev1",
-					Attributes: []core.KeyValue{
-						key.Uint64("eventattr1", 123),
+					Attributes: []kv.KeyValue{
+						kv.Uint64("eventattr1", 123),
 					},
 				},
 				{
@@ -266,9 +265,9 @@ func TestModelConversion(t *testing.T) {
 			Name:         "foo",
 			StartTime:    time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
 			EndTime:      time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
-			Attributes: []core.KeyValue{
-				key.Uint64("attr1", 42),
-				key.String("attr2", "bar"),
+			Attributes: []kv.KeyValue{
+				kv.Uint64("attr1", 42),
+				kv.String("attr2", "bar"),
 			},
 			MessageEvents: nil,
 			StatusCode:    codes.NotFound,
@@ -285,15 +284,15 @@ func TestModelConversion(t *testing.T) {
 			Name:         "foo",
 			StartTime:    time.Date(2020, time.March, 11, 19, 24, 0, 0, time.UTC),
 			EndTime:      time.Date(2020, time.March, 11, 19, 25, 0, 0, time.UTC),
-			Attributes: []core.KeyValue{
-				key.String("error", "false"),
+			Attributes: []kv.KeyValue{
+				kv.String("error", "false"),
 			},
 			MessageEvents: []export.Event{
 				{
 					Time: time.Date(2020, time.March, 11, 19, 24, 30, 0, time.UTC),
 					Name: "ev1",
-					Attributes: []core.KeyValue{
-						key.Uint64("eventattr1", 123),
+					Attributes: []kv.KeyValue{
+						kv.Uint64("eventattr1", 123),
 					},
 				},
 				{
diff --git a/plugin/httptrace/clienttrace_test.go b/plugin/httptrace/clienttrace_test.go
index b4508cfc..adbe22bd 100644
--- a/plugin/httptrace/clienttrace_test.go
+++ b/plugin/httptrace/clienttrace_test.go
@@ -23,9 +23,8 @@ import (
 
 	"github.com/google/go-cmp/cmp"
 
-	"go.opentelemetry.io/otel/api/core"
 	"go.opentelemetry.io/otel/api/global"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/plugin/httptrace"
 	export "go.opentelemetry.io/otel/sdk/export/trace"
 	sdktrace "go.opentelemetry.io/otel/sdk/trace"
@@ -102,19 +101,19 @@ func TestHTTPRequestWithClientTrace(t *testing.T) {
 
 	testLen := []struct {
 		name       string
-		attributes []core.KeyValue
+		attributes []kv.KeyValue
 		parent     string
 	}{
 		{
 			name:       "http.connect",
-			attributes: []core.KeyValue{key.String("http.remote", address.String())},
+			attributes: []kv.KeyValue{kv.String("http.remote", address.String())},
 			parent:     "http.getconn",
 		},
 		{
 			name: "http.getconn",
-			attributes: []core.KeyValue{
-				key.String("http.remote", address.String()),
-				key.String("http.host", address.String()),
+			attributes: []kv.KeyValue{
+				kv.String("http.remote", address.String()),
+				kv.String("http.host", address.String()),
 			},
 			parent: "test",
 		},
@@ -141,18 +140,18 @@ func TestHTTPRequestWithClientTrace(t *testing.T) {
 			}
 		}
 
-		actualAttrs := make(map[core.Key]string)
+		actualAttrs := make(map[kv.Key]string)
 		for _, attr := range span.Attributes {
 			actualAttrs[attr.Key] = attr.Value.Emit()
 		}
 
-		expectedAttrs := make(map[core.Key]string)
+		expectedAttrs := make(map[kv.Key]string)
 		for _, attr := range tl.attributes {
 			expectedAttrs[attr.Key] = attr.Value.Emit()
 		}
 
 		if tl.name == "http.getconn" {
-			local := key.New("http.local")
+			local := kv.NewKey("http.local")
 			// http.local attribute is not deterministic, just make sure it exists for `getconn`.
 			if _, ok := actualAttrs[local]; ok {
 				delete(actualAttrs, local)
diff --git a/plugin/othttp/handler_example_test.go b/plugin/othttp/handler_example_test.go
index 63e61083..96f374db 100644
--- a/plugin/othttp/handler_example_test.go
+++ b/plugin/othttp/handler_example_test.go
@@ -22,8 +22,9 @@ import (
 	"net/http"
 	"strings"
 
+	"go.opentelemetry.io/otel/api/kv"
+
 	"go.opentelemetry.io/otel/api/global"
-	"go.opentelemetry.io/otel/api/key"
 	"go.opentelemetry.io/otel/api/trace"
 	"go.opentelemetry.io/otel/exporters/trace/stdout"
 	"go.opentelemetry.io/otel/plugin/othttp"
@@ -65,7 +66,7 @@ func ExampleNewHandler() {
 		case "":
 			err = fmt.Errorf("expected /hello/:name in %q", s)
 		default:
-			trace.SpanFromContext(ctx).SetAttributes(key.String("name", pp[1]))
+			trace.SpanFromContext(ctx).SetAttributes(kv.String("name", pp[1]))
 		}
 		return pp[1], err
 	}
diff --git a/sdk/export/metric/metric_test.go b/sdk/export/metric/metric_test.go
index b172cf2e..bfb575e3 100644
--- a/sdk/export/metric/metric_test.go
+++ b/sdk/export/metric/metric_test.go
@@ -17,19 +17,18 @@ package metric
 import (
 	"testing"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/label"
 
 	"github.com/stretchr/testify/require"
 )
 
-var testSlice = []core.KeyValue{
-	key.String("bar", "baz"),
-	key.Int("foo", 42),
+var testSlice = []kv.KeyValue{
+	kv.String("bar", "baz"),
+	kv.Int("foo", 42),
 }
 
-func newIter(slice []core.KeyValue) label.Iterator {
+func newIter(slice []kv.KeyValue) label.Iterator {
 	labels := label.NewSet(slice...)
 	return labels.Iter()
 }
@@ -39,17 +38,17 @@ func TestLabelIterator(t *testing.T) {
 	require.Equal(t, 2, iter.Len())
 
 	require.True(t, iter.Next())
-	require.Equal(t, key.String("bar", "baz"), iter.Label())
+	require.Equal(t, kv.String("bar", "baz"), iter.Label())
 	idx, label := iter.IndexedLabel()
 	require.Equal(t, 0, idx)
-	require.Equal(t, key.String("bar", "baz"), label)
+	require.Equal(t, kv.String("bar", "baz"), label)
 	require.Equal(t, 2, iter.Len())
 
 	require.True(t, iter.Next())
-	require.Equal(t, key.Int("foo", 42), iter.Label())
+	require.Equal(t, kv.Int("foo", 42), iter.Label())
 	idx, label = iter.IndexedLabel()
 	require.Equal(t, 1, idx)
-	require.Equal(t, key.Int("foo", 42), label)
+	require.Equal(t, kv.Int("foo", 42), label)
 	require.Equal(t, 2, iter.Len())
 
 	require.False(t, iter.Next())
diff --git a/sdk/metric/benchmark_test.go b/sdk/metric/benchmark_test.go
index c02ac1ec..aa0cb1c1 100644
--- a/sdk/metric/benchmark_test.go
+++ b/sdk/metric/benchmark_test.go
@@ -21,8 +21,7 @@ import (
 	"strings"
 	"testing"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/label"
 	"go.opentelemetry.io/otel/api/metric"
 	export "go.opentelemetry.io/otel/sdk/export/metric"
@@ -90,8 +89,8 @@ func (*benchFixture) CheckpointSet() export.CheckpointSet {
 func (*benchFixture) FinishedCollection() {
 }
 
-func makeManyLabels(n int) [][]core.KeyValue {
-	r := make([][]core.KeyValue, n)
+func makeManyLabels(n int) [][]kv.KeyValue {
+	r := make([][]kv.KeyValue, n)
 
 	for i := 0; i < n; i++ {
 		r[i] = makeLabels(1)
@@ -100,9 +99,9 @@ func makeManyLabels(n int) [][]core.KeyValue {
 	return r
 }
 
-func makeLabels(n int) []core.KeyValue {
+func makeLabels(n int) []kv.KeyValue {
 	used := map[string]bool{}
-	l := make([]core.KeyValue, n)
+	l := make([]kv.KeyValue, n)
 	for i := 0; i < n; i++ {
 		var k string
 		for {
@@ -112,7 +111,7 @@ func makeLabels(n int) []core.KeyValue {
 				break
 			}
 		}
-		l[i] = key.New(k).String(fmt.Sprint("v", rand.Intn(1000000000)))
+		l[i] = kv.NewKey(k).String(fmt.Sprint("v", rand.Intn(1000000000)))
 	}
 	return l
 }
@@ -199,12 +198,12 @@ func BenchmarkAcquireReleaseExistingHandle(b *testing.B) {
 
 // Iterators
 
-var benchmarkIteratorVar core.KeyValue
+var benchmarkIteratorVar kv.KeyValue
 
 func benchmarkIterator(b *testing.B, n int) {
 	fix := newFixture(b)
 	fix.setProcessCallback(func(ctx context.Context, rec export.Record) error {
-		var kv core.KeyValue
+		var kv kv.KeyValue
 		li := rec.Labels().Iter()
 		fix.B.StartTimer()
 		for i := 0; i < fix.B.N; i++ {
@@ -568,7 +567,7 @@ func BenchmarkRepeatedDirectCalls(b *testing.B) {
 	}
 
 	c := fix.meter.NewInt64Counter("int64.counter")
-	k := key.String("bench", "true")
+	k := kv.String("bench", "true")
 
 	b.ResetTimer()
 
@@ -601,7 +600,7 @@ func BenchmarkLabelIterator(b *testing.B) {
 
 	labels := rec.Labels()
 	iter := labels.Iter()
-	var val core.KeyValue
+	var val kv.KeyValue
 	for i := 0; i < b.N; i++ {
 		if !iter.Next() {
 			iter = labels.Iter()
diff --git a/sdk/metric/controller/push/config_test.go b/sdk/metric/controller/push/config_test.go
index e0d5986d..f96b4a28 100644
--- a/sdk/metric/controller/push/config_test.go
+++ b/sdk/metric/controller/push/config_test.go
@@ -18,9 +18,10 @@ import (
 	"fmt"
 	"testing"
 
+	"go.opentelemetry.io/otel/api/kv"
+
 	"github.com/stretchr/testify/assert"
 
-	"go.opentelemetry.io/otel/api/key"
 	sdk "go.opentelemetry.io/otel/sdk/metric"
 	"go.opentelemetry.io/otel/sdk/resource"
 )
@@ -49,7 +50,7 @@ func TestWithErrorHandler(t *testing.T) {
 }
 
 func TestWithResource(t *testing.T) {
-	r := resource.New(key.String("A", "a"))
+	r := resource.New(kv.String("A", "a"))
 
 	c := &Config{}
 	WithResource(r).Apply(c)
diff --git a/sdk/metric/correct_test.go b/sdk/metric/correct_test.go
index b9e218e0..971c5815 100644
--- a/sdk/metric/correct_test.go
+++ b/sdk/metric/correct_test.go
@@ -24,8 +24,7 @@ import (
 
 	"github.com/stretchr/testify/require"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/label"
 	"go.opentelemetry.io/otel/api/metric"
 	export "go.opentelemetry.io/otel/sdk/export/metric"
@@ -195,19 +194,19 @@ func TestSDKLabelsDeduplication(t *testing.T) {
 		keySets = 2
 		repeats = 3
 	)
-	var keysA []core.Key
-	var keysB []core.Key
+	var keysA []kv.Key
+	var keysB []kv.Key
 
 	for i := 0; i < maxKeys; i++ {
-		keysA = append(keysA, core.Key(fmt.Sprintf("A%03d", i)))
-		keysB = append(keysB, core.Key(fmt.Sprintf("B%03d", i)))
+		keysA = append(keysA, kv.Key(fmt.Sprintf("A%03d", i)))
+		keysB = append(keysB, kv.Key(fmt.Sprintf("B%03d", i)))
 	}
 
-	var allExpect [][]core.KeyValue
+	var allExpect [][]kv.KeyValue
 	for numKeys := 0; numKeys < maxKeys; numKeys++ {
 
-		var kvsA []core.KeyValue
-		var kvsB []core.KeyValue
+		var kvsA []kv.KeyValue
+		var kvsB []kv.KeyValue
 		for r := 0; r < repeats; r++ {
 			for i := 0; i < numKeys; i++ {
 				kvsA = append(kvsA, keysA[i].Int(r))
@@ -215,8 +214,8 @@ func TestSDKLabelsDeduplication(t *testing.T) {
 			}
 		}
 
-		var expectA []core.KeyValue
-		var expectB []core.KeyValue
+		var expectA []kv.KeyValue
+		var expectB []kv.KeyValue
 		for i := 0; i < numKeys; i++ {
 			expectA = append(expectA, keysA[i].Int(repeats-1))
 			expectB = append(expectB, keysB[i].Int(repeats-1))
@@ -237,7 +236,7 @@ func TestSDKLabelsDeduplication(t *testing.T) {
 
 	sdk.Collect(ctx)
 
-	var actual [][]core.KeyValue
+	var actual [][]kv.KeyValue
 	for _, rec := range integrator.records {
 		sum, _ := rec.Aggregator().(aggregator.Sum).Sum()
 		require.Equal(t, sum, metric.NewInt64Number(2))
@@ -249,7 +248,7 @@ func TestSDKLabelsDeduplication(t *testing.T) {
 	require.ElementsMatch(t, allExpect, actual)
 }
 
-func newSetIter(kvs ...core.KeyValue) label.Iterator {
+func newSetIter(kvs ...kv.KeyValue) label.Iterator {
 	labels := label.NewSet(kvs...)
 	return labels.Iter()
 }
@@ -257,28 +256,28 @@ func newSetIter(kvs ...core.KeyValue) label.Iterator {
 func TestDefaultLabelEncoder(t *testing.T) {
 	encoder := label.DefaultEncoder()
 
-	encoded := encoder.Encode(newSetIter(key.String("A", "B"), key.String("C", "D")))
+	encoded := encoder.Encode(newSetIter(kv.String("A", "B"), kv.String("C", "D")))
 	require.Equal(t, `A=B,C=D`, encoded)
 
-	encoded = encoder.Encode(newSetIter(key.String("A", "B,c=d"), key.String(`C\`, "D")))
+	encoded = encoder.Encode(newSetIter(kv.String("A", "B,c=d"), kv.String(`C\`, "D")))
 	require.Equal(t, `A=B\,c\=d,C\\=D`, encoded)
 
-	encoded = encoder.Encode(newSetIter(key.String(`\`, `=`), key.String(`,`, `\`)))
+	encoded = encoder.Encode(newSetIter(kv.String(`\`, `=`), kv.String(`,`, `\`)))
 	require.Equal(t, `\,=\\,\\=\=`, encoded)
 
 	// Note: the label encoder does not sort or de-dup values,
 	// that is done in Labels(...).
 	encoded = encoder.Encode(newSetIter(
-		key.Int("I", 1),
-		key.Uint("U", 1),
-		key.Int32("I32", 1),
-		key.Uint32("U32", 1),
-		key.Int64("I64", 1),
-		key.Uint64("U64", 1),
-		key.Float64("F64", 1),
-		key.Float64("F64", 1),
-		key.String("S", "1"),
-		key.Bool("B", true),
+		kv.Int("I", 1),
+		kv.Uint("U", 1),
+		kv.Int32("I32", 1),
+		kv.Uint32("U32", 1),
+		kv.Int64("I64", 1),
+		kv.Uint64("U64", 1),
+		kv.Float64("F64", 1),
+		kv.Float64("F64", 1),
+		kv.String("S", "1"),
+		kv.Bool("B", true),
 	))
 	require.Equal(t, "B=true,F64=1,I=1,I32=1,I64=1,S=1,U=1,U32=1,U64=1", encoded)
 }
@@ -293,16 +292,16 @@ func TestObserverCollection(t *testing.T) {
 	meter := metric.WrapMeterImpl(sdk, "test")
 
 	_ = Must(meter).RegisterFloat64Observer("float.observer", func(result metric.Float64ObserverResult) {
-		result.Observe(1, key.String("A", "B"))
+		result.Observe(1, kv.String("A", "B"))
 		// last value wins
-		result.Observe(-1, key.String("A", "B"))
-		result.Observe(-1, key.String("C", "D"))
+		result.Observe(-1, kv.String("A", "B"))
+		result.Observe(-1, kv.String("C", "D"))
 	})
 	_ = Must(meter).RegisterInt64Observer("int.observer", func(result metric.Int64ObserverResult) {
-		result.Observe(-1, key.String("A", "B"))
+		result.Observe(-1, kv.String("A", "B"))
 		result.Observe(1)
 		// last value wins
-		result.Observe(1, key.String("A", "B"))
+		result.Observe(1, kv.String("A", "B"))
 		result.Observe(1)
 	})
 	_ = Must(meter).RegisterInt64Observer("empty.observer", func(result metric.Int64ObserverResult) {
@@ -341,9 +340,9 @@ func TestRecordBatch(t *testing.T) {
 
 	sdk.RecordBatch(
 		ctx,
-		[]core.KeyValue{
-			key.String("A", "B"),
-			key.String("C", "D"),
+		[]kv.KeyValue{
+			kv.String("A", "B"),
+			kv.String("C", "D"),
 		},
 		counter1.Measurement(1),
 		counter2.Measurement(2),
@@ -378,8 +377,8 @@ func TestRecordPersistence(t *testing.T) {
 	meter := metric.WrapMeterImpl(sdk, "test")
 
 	c := Must(meter).NewFloat64Counter("sum.name")
-	b := c.Bind(key.String("bound", "true"))
-	uk := key.String("bound", "false")
+	b := c.Bind(kv.String("bound", "true"))
+	uk := kv.String("bound", "false")
 
 	for i := 0; i < 100; i++ {
 		c.Add(ctx, 1, uk)
diff --git a/sdk/metric/example_test.go b/sdk/metric/example_test.go
index 7c84ca7f..b960b83f 100644
--- a/sdk/metric/example_test.go
+++ b/sdk/metric/example_test.go
@@ -19,7 +19,8 @@ import (
 	"fmt"
 	"time"
 
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
+
 	"go.opentelemetry.io/otel/api/metric"
 	"go.opentelemetry.io/otel/exporters/metric/stdout"
 )
@@ -36,7 +37,7 @@ func ExampleNew() {
 
 	ctx := context.Background()
 
-	key := key.New("key")
+	key := kv.NewKey("key")
 	meter := pusher.Meter("example")
 
 	counter := metric.Must(meter).NewInt64Counter("a.counter")
diff --git a/sdk/metric/integrator/test/test.go b/sdk/metric/integrator/test/test.go
index 8ee89366..8d6fe0cd 100644
--- a/sdk/metric/integrator/test/test.go
+++ b/sdk/metric/integrator/test/test.go
@@ -19,8 +19,7 @@ import (
 	"fmt"
 	"strings"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/label"
 	"go.opentelemetry.io/otel/api/metric"
 	export "go.opentelemetry.io/otel/sdk/export/metric"
@@ -66,9 +65,9 @@ var (
 	// Counter groups are (labels1+labels2), (labels3)
 
 	// Labels1 has G=H and C=D
-	Labels1 = makeLabels(key.String("G", "H"), key.String("C", "D"))
+	Labels1 = makeLabels(kv.String("G", "H"), kv.String("C", "D"))
 	// Labels2 has C=D and E=F
-	Labels2 = makeLabels(key.String("C", "D"), key.String("E", "F"))
+	Labels2 = makeLabels(kv.String("C", "D"), kv.String("E", "F"))
 	// Labels3 is the empty set
 	Labels3 = makeLabels()
 
@@ -83,8 +82,8 @@ func NewOutput(labelEncoder label.Encoder) Output {
 }
 
 // NewAggregationSelector returns a policy that is consistent with the
-// test descriptors above.  I.e., it returns sum.New() for counter
-// instruments and lastvalue.New for lastValue instruments.
+// test descriptors above.  I.e., it returns sum.NewKey() for counter
+// instruments and lastvalue.NewKey for lastValue instruments.
 func NewAggregationSelector() export.AggregationSelector {
 	return &testAggregationSelector{}
 }
@@ -100,7 +99,7 @@ func (*testAggregationSelector) AggregatorFor(desc *metric.Descriptor) export.Ag
 	}
 }
 
-func makeLabels(labels ...core.KeyValue) *label.Set {
+func makeLabels(labels ...kv.KeyValue) *label.Set {
 	s := label.NewSet(labels...)
 	return &s
 }
diff --git a/sdk/metric/stress_test.go b/sdk/metric/stress_test.go
index 7068cdcf..bdda93fa 100644
--- a/sdk/metric/stress_test.go
+++ b/sdk/metric/stress_test.go
@@ -31,8 +31,7 @@ import (
 	"testing"
 	"time"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/metric"
 	api "go.opentelemetry.io/otel/api/metric"
 	export "go.opentelemetry.io/otel/sdk/export/metric"
@@ -75,7 +74,7 @@ type (
 	testImpl struct {
 		newInstrument  func(meter api.Meter, name string) SyncImpler
 		getUpdateValue func() api.Number
-		operate        func(interface{}, context.Context, api.Number, []core.KeyValue)
+		operate        func(interface{}, context.Context, api.Number, []kv.KeyValue)
 		newStore       func() interface{}
 
 		// storeCollect and storeExpect are the same for
@@ -105,7 +104,7 @@ func concurrency() int {
 	return concurrencyPerCPU * runtime.NumCPU()
 }
 
-func canonicalizeLabels(ls []core.KeyValue) string {
+func canonicalizeLabels(ls []kv.KeyValue) string {
 	copy := append(ls[0:0:0], ls...)
 	sort.SliceStable(copy, func(i, j int) bool {
 		return copy[i].Key < copy[j].Key
@@ -128,9 +127,9 @@ func getPeriod() time.Duration {
 	return time.Duration(dur)
 }
 
-func (f *testFixture) someLabels() []core.KeyValue {
+func (f *testFixture) someLabels() []kv.KeyValue {
 	n := 1 + rand.Intn(3)
-	l := make([]core.KeyValue, n)
+	l := make([]kv.KeyValue, n)
 
 	for {
 		oused := map[string]bool{}
@@ -143,7 +142,7 @@ func (f *testFixture) someLabels() []core.KeyValue {
 					break
 				}
 			}
-			l[i] = key.New(k).String(fmt.Sprint("v", rand.Intn(1000000000)))
+			l[i] = kv.NewKey(k).String(fmt.Sprint("v", rand.Intn(1000000000)))
 		}
 		lc := canonicalizeLabels(l)
 		f.lock.Lock()
@@ -364,7 +363,7 @@ func intCounterTestImpl() testImpl {
 				}
 			}
 		},
-		operate: func(inst interface{}, ctx context.Context, value api.Number, labels []core.KeyValue) {
+		operate: func(inst interface{}, ctx context.Context, value api.Number, labels []kv.KeyValue) {
 			counter := inst.(api.Int64Counter)
 			counter.Add(ctx, value.AsInt64(), labels...)
 		},
@@ -402,7 +401,7 @@ func floatCounterTestImpl() testImpl {
 				}
 			}
 		},
-		operate: func(inst interface{}, ctx context.Context, value api.Number, labels []core.KeyValue) {
+		operate: func(inst interface{}, ctx context.Context, value api.Number, labels []kv.KeyValue) {
 			counter := inst.(api.Float64Counter)
 			counter.Add(ctx, value.AsFloat64(), labels...)
 		},
@@ -438,7 +437,7 @@ func intLastValueTestImpl() testImpl {
 			r1 := rand.Int63()
 			return api.NewInt64Number(rand.Int63() - r1)
 		},
-		operate: func(inst interface{}, ctx context.Context, value api.Number, labels []core.KeyValue) {
+		operate: func(inst interface{}, ctx context.Context, value api.Number, labels []kv.KeyValue) {
 			measure := inst.(api.Int64Measure)
 			measure.Record(ctx, value.AsInt64(), labels...)
 		},
@@ -479,7 +478,7 @@ func floatLastValueTestImpl() testImpl {
 		getUpdateValue: func() api.Number {
 			return api.NewFloat64Number((-0.5 + rand.Float64()) * 100000)
 		},
-		operate: func(inst interface{}, ctx context.Context, value api.Number, labels []core.KeyValue) {
+		operate: func(inst interface{}, ctx context.Context, value api.Number, labels []kv.KeyValue) {
 			measure := inst.(api.Float64Measure)
 			measure.Record(ctx, value.AsFloat64(), labels...)
 		},
diff --git a/sdk/resource/resource_test.go b/sdk/resource/resource_test.go
index ae45de44..1bb717b4 100644
--- a/sdk/resource/resource_test.go
+++ b/sdk/resource/resource_test.go
@@ -19,40 +19,41 @@ import (
 	"fmt"
 	"testing"
 
+	"go.opentelemetry.io/otel/api/kv/value"
+
 	"github.com/google/go-cmp/cmp"
 	"github.com/stretchr/testify/require"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/sdk/resource"
 )
 
 var (
-	kv11 = key.String("k1", "v11")
-	kv12 = key.String("k1", "v12")
-	kv21 = key.String("k2", "v21")
-	kv31 = key.String("k3", "v31")
-	kv41 = key.String("k4", "v41")
+	kv11 = kv.String("k1", "v11")
+	kv12 = kv.String("k1", "v12")
+	kv21 = kv.String("k2", "v21")
+	kv31 = kv.String("k3", "v31")
+	kv41 = kv.String("k4", "v41")
 )
 
 func TestNew(t *testing.T) {
 	cases := []struct {
 		name string
-		in   []core.KeyValue
-		want []core.KeyValue
+		in   []kv.KeyValue
+		want []kv.KeyValue
 	}{
 		{
-			name: "New with common key order1",
-			in:   []core.KeyValue{kv12, kv11, kv21},
-			want: []core.KeyValue{kv11, kv21},
+			name: "NewKey with common key order1",
+			in:   []kv.KeyValue{kv12, kv11, kv21},
+			want: []kv.KeyValue{kv11, kv21},
 		},
 		{
-			name: "New with common key order2",
-			in:   []core.KeyValue{kv11, kv12, kv21},
-			want: []core.KeyValue{kv12, kv21},
+			name: "NewKey with common key order2",
+			in:   []kv.KeyValue{kv11, kv12, kv21},
+			want: []kv.KeyValue{kv12, kv21},
 		},
 		{
-			name: "New with nil",
+			name: "NewKey with nil",
 			in:   nil,
 			want: nil,
 		},
@@ -63,7 +64,7 @@ func TestNew(t *testing.T) {
 			if diff := cmp.Diff(
 				res.Attributes(),
 				c.want,
-				cmp.AllowUnexported(core.Value{})); diff != "" {
+				cmp.AllowUnexported(value.Value{})); diff != "" {
 				t.Fatalf("unwanted result: diff %+v,", diff)
 			}
 		})
@@ -74,37 +75,37 @@ func TestMerge(t *testing.T) {
 	cases := []struct {
 		name string
 		a, b *resource.Resource
-		want []core.KeyValue
+		want []kv.KeyValue
 	}{
 		{
 			name: "Merge with no overlap, no nil",
 			a:    resource.New(kv11, kv31),
 			b:    resource.New(kv21, kv41),
-			want: []core.KeyValue{kv11, kv21, kv31, kv41},
+			want: []kv.KeyValue{kv11, kv21, kv31, kv41},
 		},
 		{
 			name: "Merge with no overlap, no nil, not interleaved",
 			a:    resource.New(kv11, kv21),
 			b:    resource.New(kv31, kv41),
-			want: []core.KeyValue{kv11, kv21, kv31, kv41},
+			want: []kv.KeyValue{kv11, kv21, kv31, kv41},
 		},
 		{
 			name: "Merge with common key order1",
 			a:    resource.New(kv11),
 			b:    resource.New(kv12, kv21),
-			want: []core.KeyValue{kv11, kv21},
+			want: []kv.KeyValue{kv11, kv21},
 		},
 		{
 			name: "Merge with common key order2",
 			a:    resource.New(kv12, kv21),
 			b:    resource.New(kv11),
-			want: []core.KeyValue{kv12, kv21},
+			want: []kv.KeyValue{kv12, kv21},
 		},
 		{
 			name: "Merge with common key order4",
 			a:    resource.New(kv11, kv21, kv41),
 			b:    resource.New(kv31, kv41),
-			want: []core.KeyValue{kv11, kv21, kv31, kv41},
+			want: []kv.KeyValue{kv11, kv21, kv31, kv41},
 		},
 		{
 			name: "Merge with no keys",
@@ -116,25 +117,25 @@ func TestMerge(t *testing.T) {
 			name: "Merge with first resource no keys",
 			a:    resource.New(),
 			b:    resource.New(kv21),
-			want: []core.KeyValue{kv21},
+			want: []kv.KeyValue{kv21},
 		},
 		{
 			name: "Merge with second resource no keys",
 			a:    resource.New(kv11),
 			b:    resource.New(),
-			want: []core.KeyValue{kv11},
+			want: []kv.KeyValue{kv11},
 		},
 		{
 			name: "Merge with first resource nil",
 			a:    nil,
 			b:    resource.New(kv21),
-			want: []core.KeyValue{kv21},
+			want: []kv.KeyValue{kv21},
 		},
 		{
 			name: "Merge with second resource nil",
 			a:    resource.New(kv11),
 			b:    nil,
-			want: []core.KeyValue{kv11},
+			want: []kv.KeyValue{kv11},
 		},
 	}
 	for _, c := range cases {
@@ -143,7 +144,7 @@ func TestMerge(t *testing.T) {
 			if diff := cmp.Diff(
 				res.Attributes(),
 				c.want,
-				cmp.AllowUnexported(core.Value{})); diff != "" {
+				cmp.AllowUnexported(value.Value{})); diff != "" {
 				t.Fatalf("unwanted result: diff %+v,", diff)
 			}
 		})
@@ -152,7 +153,7 @@ func TestMerge(t *testing.T) {
 
 func TestString(t *testing.T) {
 	for _, test := range []struct {
-		kvs  []core.KeyValue
+		kvs  []kv.KeyValue
 		want string
 	}{
 		{
@@ -160,51 +161,51 @@ func TestString(t *testing.T) {
 			want: "",
 		},
 		{
-			kvs:  []core.KeyValue{},
+			kvs:  []kv.KeyValue{},
 			want: "",
 		},
 		{
-			kvs:  []core.KeyValue{kv11},
+			kvs:  []kv.KeyValue{kv11},
 			want: "k1=v11",
 		},
 		{
-			kvs:  []core.KeyValue{kv11, kv12},
+			kvs:  []kv.KeyValue{kv11, kv12},
 			want: "k1=v12",
 		},
 		{
-			kvs:  []core.KeyValue{kv11, kv21},
+			kvs:  []kv.KeyValue{kv11, kv21},
 			want: "k1=v11,k2=v21",
 		},
 		{
-			kvs:  []core.KeyValue{kv21, kv11},
+			kvs:  []kv.KeyValue{kv21, kv11},
 			want: "k1=v11,k2=v21",
 		},
 		{
-			kvs:  []core.KeyValue{kv11, kv21, kv31},
+			kvs:  []kv.KeyValue{kv11, kv21, kv31},
 			want: "k1=v11,k2=v21,k3=v31",
 		},
 		{
-			kvs:  []core.KeyValue{kv31, kv11, kv21},
+			kvs:  []kv.KeyValue{kv31, kv11, kv21},
 			want: "k1=v11,k2=v21,k3=v31",
 		},
 		{
-			kvs:  []core.KeyValue{key.String("A", "a"), key.String("B", "b")},
+			kvs:  []kv.KeyValue{kv.String("A", "a"), kv.String("B", "b")},
 			want: "A=a,B=b",
 		},
 		{
-			kvs:  []core.KeyValue{key.String("A", "a,B=b")},
+			kvs:  []kv.KeyValue{kv.String("A", "a,B=b")},
 			want: `A=a\,B\=b`,
 		},
 		{
-			kvs:  []core.KeyValue{key.String("A", `a,B\=b`)},
+			kvs:  []kv.KeyValue{kv.String("A", `a,B\=b`)},
 			want: `A=a\,B\\\=b`,
 		},
 		{
-			kvs:  []core.KeyValue{key.String("A=a,B", `b`)},
+			kvs:  []kv.KeyValue{kv.String("A=a,B", `b`)},
 			want: `A\=a\,B=b`,
 		},
 		{
-			kvs:  []core.KeyValue{key.String(`A=a\,B`, `b`)},
+			kvs:  []kv.KeyValue{kv.String(`A=a\,B`, `b`)},
 			want: `A\=a\\\,B=b`,
 		},
 	} {
@@ -215,7 +216,7 @@ func TestString(t *testing.T) {
 }
 
 func TestMarshalJSON(t *testing.T) {
-	r := resource.New(key.Int64("A", 1), key.String("C", "D"))
+	r := resource.New(kv.Int64("A", 1), kv.String("C", "D"))
 	data, err := json.Marshal(r)
 	require.NoError(t, err)
 	require.Equal(t,
diff --git a/sdk/trace/benchmark_test.go b/sdk/trace/benchmark_test.go
index 1690d09f..f9bbbfa4 100644
--- a/sdk/trace/benchmark_test.go
+++ b/sdk/trace/benchmark_test.go
@@ -18,7 +18,8 @@ import (
 	"context"
 	"testing"
 
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
+
 	apitrace "go.opentelemetry.io/otel/api/trace"
 	sdktrace "go.opentelemetry.io/otel/sdk/trace"
 )
@@ -42,10 +43,10 @@ func BenchmarkSpanWithAttributes_4(b *testing.B) {
 		for i := 0; i < b.N; i++ {
 			_, span := t.Start(ctx, "/foo")
 			span.SetAttributes(
-				key.New("key1").Bool(false),
-				key.New("key2").String("hello"),
-				key.New("key3").Uint64(123),
-				key.New("key4").Float64(123.456),
+				kv.NewKey("key1").Bool(false),
+				kv.NewKey("key2").String("hello"),
+				kv.NewKey("key3").Uint64(123),
+				kv.NewKey("key4").Float64(123.456),
 			)
 			span.End()
 		}
@@ -60,14 +61,14 @@ func BenchmarkSpanWithAttributes_8(b *testing.B) {
 		for i := 0; i < b.N; i++ {
 			_, span := t.Start(ctx, "/foo")
 			span.SetAttributes(
-				key.New("key1").Bool(false),
-				key.New("key2").String("hello"),
-				key.New("key3").Uint64(123),
-				key.New("key4").Float64(123.456),
-				key.New("key21").Bool(false),
-				key.New("key22").String("hello"),
-				key.New("key23").Uint64(123),
-				key.New("key24").Float64(123.456),
+				kv.NewKey("key1").Bool(false),
+				kv.NewKey("key2").String("hello"),
+				kv.NewKey("key3").Uint64(123),
+				kv.NewKey("key4").Float64(123.456),
+				kv.NewKey("key21").Bool(false),
+				kv.NewKey("key22").String("hello"),
+				kv.NewKey("key23").Uint64(123),
+				kv.NewKey("key24").Float64(123.456),
 			)
 			span.End()
 		}
@@ -82,16 +83,16 @@ func BenchmarkSpanWithAttributes_all(b *testing.B) {
 		for i := 0; i < b.N; i++ {
 			_, span := t.Start(ctx, "/foo")
 			span.SetAttributes(
-				key.New("key1").Bool(false),
-				key.New("key2").String("hello"),
-				key.New("key3").Int64(123),
-				key.New("key4").Uint64(123),
-				key.New("key5").Int32(123),
-				key.New("key6").Uint32(123),
-				key.New("key7").Float64(123.456),
-				key.New("key8").Float32(123.456),
-				key.New("key9").Int(123),
-				key.New("key10").Uint(123),
+				kv.NewKey("key1").Bool(false),
+				kv.NewKey("key2").String("hello"),
+				kv.NewKey("key3").Int64(123),
+				kv.NewKey("key4").Uint64(123),
+				kv.NewKey("key5").Int32(123),
+				kv.NewKey("key6").Uint32(123),
+				kv.NewKey("key7").Float64(123.456),
+				kv.NewKey("key8").Float32(123.456),
+				kv.NewKey("key9").Int(123),
+				kv.NewKey("key10").Uint(123),
 			)
 			span.End()
 		}
@@ -106,26 +107,26 @@ func BenchmarkSpanWithAttributes_all_2x(b *testing.B) {
 		for i := 0; i < b.N; i++ {
 			_, span := t.Start(ctx, "/foo")
 			span.SetAttributes(
-				key.New("key1").Bool(false),
-				key.New("key2").String("hello"),
-				key.New("key3").Int64(123),
-				key.New("key4").Uint64(123),
-				key.New("key5").Int32(123),
-				key.New("key6").Uint32(123),
-				key.New("key7").Float64(123.456),
-				key.New("key8").Float32(123.456),
-				key.New("key10").Int(123),
-				key.New("key11").Uint(123),
-				key.New("key21").Bool(false),
-				key.New("key22").String("hello"),
-				key.New("key23").Int64(123),
-				key.New("key24").Uint64(123),
-				key.New("key25").Int32(123),
-				key.New("key26").Uint32(123),
-				key.New("key27").Float64(123.456),
-				key.New("key28").Float32(123.456),
-				key.New("key210").Int(123),
-				key.New("key211").Uint(123),
+				kv.NewKey("key1").Bool(false),
+				kv.NewKey("key2").String("hello"),
+				kv.NewKey("key3").Int64(123),
+				kv.NewKey("key4").Uint64(123),
+				kv.NewKey("key5").Int32(123),
+				kv.NewKey("key6").Uint32(123),
+				kv.NewKey("key7").Float64(123.456),
+				kv.NewKey("key8").Float32(123.456),
+				kv.NewKey("key10").Int(123),
+				kv.NewKey("key11").Uint(123),
+				kv.NewKey("key21").Bool(false),
+				kv.NewKey("key22").String("hello"),
+				kv.NewKey("key23").Int64(123),
+				kv.NewKey("key24").Uint64(123),
+				kv.NewKey("key25").Int32(123),
+				kv.NewKey("key26").Uint32(123),
+				kv.NewKey("key27").Float64(123.456),
+				kv.NewKey("key28").Float32(123.456),
+				kv.NewKey("key210").Int(123),
+				kv.NewKey("key211").Uint(123),
 			)
 			span.End()
 		}
diff --git a/sdk/trace/trace_test.go b/sdk/trace/trace_test.go
index c96d6bce..19e7f20a 100644
--- a/sdk/trace/trace_test.go
+++ b/sdk/trace/trace_test.go
@@ -24,11 +24,12 @@ import (
 	"testing"
 	"time"
 
+	"go.opentelemetry.io/otel/api/kv/value"
+
 	"github.com/google/go-cmp/cmp"
 	"google.golang.org/grpc/codes"
 
-	"go.opentelemetry.io/otel/api/core"
-	"go.opentelemetry.io/otel/api/key"
+	"go.opentelemetry.io/otel/api/kv"
 	"go.opentelemetry.io/otel/api/testharness"
 	"go.opentelemetry.io/otel/api/trace"
 	apitrace "go.opentelemetry.io/otel/api/trace"
@@ -81,7 +82,7 @@ func (ts *testSampler) ShouldSample(p SamplingParameters) SamplingResult {
 	if strings.HasPrefix(p.Name, ts.prefix) {
 		decision = RecordAndSampled
 	}
-	return SamplingResult{Decision: decision, Attributes: []core.KeyValue{key.Int("callCount", ts.callCount)}}
+	return SamplingResult{Decision: decision, Attributes: []kv.KeyValue{kv.Int("callCount", ts.callCount)}}
 }
 
 func (ts testSampler) Description() string {
@@ -274,8 +275,8 @@ func TestSetSpanAttributesOnStart(t *testing.T) {
 	tp, _ := NewProvider(WithSyncer(te))
 	span := startSpan(tp,
 		"StartSpanAttribute",
-		apitrace.WithAttributes(key.String("key1", "value1")),
-		apitrace.WithAttributes(key.String("key2", "value2")),
+		apitrace.WithAttributes(kv.String("key1", "value1")),
+		apitrace.WithAttributes(kv.String("key2", "value2")),
 	)
 	got, err := endSpan(te, span)
 	if err != nil {
@@ -289,9 +290,9 @@ func TestSetSpanAttributesOnStart(t *testing.T) {
 		},
 		ParentSpanID: sid,
 		Name:         "span0",
-		Attributes: []core.KeyValue{
-			key.String("key1", "value1"),
-			key.String("key2", "value2"),
+		Attributes: []kv.KeyValue{
+			kv.String("key1", "value1"),
+			kv.String("key2", "value2"),
 		},
 		SpanKind:        apitrace.SpanKindInternal,
 		HasRemoteParent: true,
@@ -305,7 +306,7 @@ func TestSetSpanAttributes(t *testing.T) {
 	te := &testExporter{}
 	tp, _ := NewProvider(WithSyncer(te))
 	span := startSpan(tp, "SpanAttribute")
-	span.SetAttributes(key.New("key1").String("value1"))
+	span.SetAttributes(kv.NewKey("key1").String("value1"))
 	got, err := endSpan(te, span)
 	if err != nil {
 		t.Fatal(err)
@@ -318,8 +319,8 @@ func TestSetSpanAttributes(t *testing.T) {
 		},
 		ParentSpanID: sid,
 		Name:         "span0",
-		Attributes: []core.KeyValue{
-			key.String("key1", "value1"),
+		Attributes: []kv.KeyValue{
+			kv.String("key1", "value1"),
 		},
 		SpanKind:        apitrace.SpanKindInternal,
 		HasRemoteParent: true,
@@ -336,10 +337,10 @@ func TestSetSpanAttributesOverLimit(t *testing.T) {
 
 	span := startSpan(tp, "SpanAttributesOverLimit")
 	span.SetAttributes(
-		key.Bool("key1", true),
-		key.String("key2", "value2"),
-		key.Bool("key1", false), // Replace key1.
-		key.Int64("key4", 4),    // Remove key2 and add key4
+		kv.Bool("key1", true),
+		kv.String("key2", "value2"),
+		kv.Bool("key1", false), // Replace key1.
+		kv.Int64("key4", 4),    // Remove key2 and add key4
 	)
 	got, err := endSpan(te, span)
 	if err != nil {
@@ -353,9 +354,9 @@ func TestSetSpanAttributesOverLimit(t *testing.T) {
 		},
 		ParentSpanID: sid,
 		Name:         "span0",
-		Attributes: []core.KeyValue{
-			key.Bool("key1", false),
-			key.Int64("key4", 4),
+		Attributes: []kv.KeyValue{
+			kv.Bool("key1", false),
+			kv.Int64("key4", 4),
 		},
 		SpanKind:              apitrace.SpanKindInternal,
 		HasRemoteParent:       true,
@@ -371,14 +372,14 @@ func TestEvents(t *testing.T) {
 	tp, _ := NewProvider(WithSyncer(te))
 
 	span := startSpan(tp, "Events")
-	k1v1 := key.New("key1").String("value1")
-	k2v2 := key.Bool("key2", true)
-	k3v3 := key.Int64("key3", 3)
+	k1v1 := kv.NewKey("key1").String("value1")
+	k2v2 := kv.Bool("key2", true)
+	k3v3 := kv.Int64("key3", 3)
 
-	span.AddEvent(context.Background(), "foo", key.New("key1").String("value1"))
+	span.AddEvent(context.Background(), "foo", kv.NewKey("key1").String("value1"))
 	span.AddEvent(context.Background(), "bar",
-		key.Bool("key2", true),
-		key.Int64("key3", 3),
+		kv.Bool("key2", true),
+		kv.Int64("key3", 3),
 	)
 	got, err := endSpan(te, span)
 	if err != nil {
@@ -400,8 +401,8 @@ func TestEvents(t *testing.T) {
 		Name:            "span0",
 		HasRemoteParent: true,
 		MessageEvents: []export.Event{
-			{Name: "foo", Attributes: []core.KeyValue{k1v1}},
-			{Name: "bar", Attributes: []core.KeyValue{k2v2, k3v3}},
+			{Name: "foo", Attributes: []kv.KeyValue{k1v1}},
+			{Name: "bar", Attributes: []kv.KeyValue{k2v2, k3v3}},
 		},
 		SpanKind: apitrace.SpanKindInternal,
 	}
@@ -416,19 +417,19 @@ func TestEventsOverLimit(t *testing.T) {
 	tp, _ := NewProvider(WithConfig(cfg), WithSyncer(te))
 
 	span := startSpan(tp, "EventsOverLimit")
-	k1v1 := key.New("key1").String("value1")
-	k2v2 := key.Bool("key2", false)
-	k3v3 := key.New("key3").String("value3")
+	k1v1 := kv.NewKey("key1").String("value1")
+	k2v2 := kv.Bool("key2", false)
+	k3v3 := kv.NewKey("key3").String("value3")
 
-	span.AddEvent(context.Background(), "fooDrop", key.New("key1").String("value1"))
+	span.AddEvent(context.Background(), "fooDrop", kv.NewKey("key1").String("value1"))
 	span.AddEvent(context.Background(), "barDrop",
-		key.Bool("key2", true),
-		key.New("key3").String("value3"),
+		kv.Bool("key2", true),
+		kv.NewKey("key3").String("value3"),
 	)
-	span.AddEvent(context.Background(), "foo", key.New("key1").String("value1"))
+	span.AddEvent(context.Background(), "foo", kv.NewKey("key1").String("value1"))
 	span.AddEvent(context.Background(), "bar",
-		key.Bool("key2", false),
-		key.New("key3").String("value3"),
+		kv.Bool("key2", false),
+		kv.NewKey("key3").String("value3"),
 	)
 	got, err := endSpan(te, span)
 	if err != nil {
@@ -449,8 +450,8 @@ func TestEventsOverLimit(t *testing.T) {
 		ParentSpanID: sid,
 		Name:         "span0",
 		MessageEvents: []export.Event{
-			{Name: "foo", Attributes: []core.KeyValue{k1v1}},
-			{Name: "bar", Attributes: []core.KeyValue{k2v2, k3v3}},
+			{Name: "foo", Attributes: []kv.KeyValue{k1v1}},
+			{Name: "bar", Attributes: []kv.KeyValue{k2v2, k3v3}},
 		},
 		DroppedMessageEventCount: 2,
 		HasRemoteParent:          true,
@@ -465,18 +466,18 @@ func TestLinks(t *testing.T) {
 	te := &testExporter{}
 	tp, _ := NewProvider(WithSyncer(te))
 
-	k1v1 := key.New("key1").String("value1")
-	k2v2 := key.New("key2").String("value2")
-	k3v3 := key.New("key3").String("value3")
+	k1v1 := kv.NewKey("key1").String("value1")
+	k2v2 := kv.NewKey("key2").String("value2")
+	k3v3 := kv.NewKey("key3").String("value3")
 
 	sc1 := apitrace.SpanContext{TraceID: apitrace.ID([16]byte{1, 1}), SpanID: apitrace.SpanID{3}}
 	sc2 := apitrace.SpanContext{TraceID: apitrace.ID([16]byte{1, 1}), SpanID: apitrace.SpanID{3}}
 
 	span := startSpan(tp, "Links",
-		apitrace.LinkedTo(sc1, key.New("key1").String("value1")),
+		apitrace.LinkedTo(sc1, kv.NewKey("key1").String("value1")),
 		apitrace.LinkedTo(sc2,
-			key.New("key2").String("value2"),
-			key.New("key3").String("value3"),
+			kv.NewKey("key2").String("value2"),
+			kv.NewKey("key3").String("value3"),
 		),
 	)
 
@@ -494,8 +495,8 @@ func TestLinks(t *testing.T) {
 		Name:            "span0",
 		HasRemoteParent: true,
 		Links: []apitrace.Link{
-			{SpanContext: sc1, Attributes: []core.KeyValue{k1v1}},
-			{SpanContext: sc2, Attributes: []core.KeyValue{k2v2, k3v3}},
+			{SpanContext: sc1, Attributes: []kv.KeyValue{k1v1}},
+			{SpanContext: sc2, Attributes: []kv.KeyValue{k2v2, k3v3}},
 		},
 		SpanKind: apitrace.SpanKindInternal,
 	}
@@ -515,13 +516,13 @@ func TestLinksOverLimit(t *testing.T) {
 	tp, _ := NewProvider(WithConfig(cfg), WithSyncer(te))
 
 	span := startSpan(tp, "LinksOverLimit",
-		apitrace.LinkedTo(sc1, key.New("key1").String("value1")),
-		apitrace.LinkedTo(sc2, key.New("key2").String("value2")),
-		apitrace.LinkedTo(sc3, key.New("key3").String("value3")),
+		apitrace.LinkedTo(sc1, kv.NewKey("key1").String("value1")),
+		apitrace.LinkedTo(sc2, kv.NewKey("key2").String("value2")),
+		apitrace.LinkedTo(sc3, kv.NewKey("key3").String("value3")),
 	)
 
-	k2v2 := key.New("key2").String("value2")
-	k3v3 := key.New("key3").String("value3")
+	k2v2 := kv.NewKey("key2").String("value2")
+	k3v3 := kv.NewKey("key3").String("value3")
 
 	got, err := endSpan(te, span)
 	if err != nil {
@@ -536,8 +537,8 @@ func TestLinksOverLimit(t *testing.T) {
 		ParentSpanID: sid,
 		Name:         "span0",
 		Links: []apitrace.Link{
-			{SpanContext: sc2, Attributes: []core.KeyValue{k2v2}},
-			{SpanContext: sc3, Attributes: []core.KeyValue{k3v3}},
+			{SpanContext: sc2, Attributes: []kv.KeyValue{k2v2}},
+			{SpanContext: sc3, Attributes: []kv.KeyValue{k3v3}},
 		},
 		DroppedLinkCount: 1,
 		HasRemoteParent:  true,
@@ -600,7 +601,7 @@ func TestSetSpanStatus(t *testing.T) {
 
 func cmpDiff(x, y interface{}) string {
 	return cmp.Diff(x, y,
-		cmp.AllowUnexported(core.Value{}),
+		cmp.AllowUnexported(value.Value{}),
 		cmp.AllowUnexported(export.Event{}))
 }
 
@@ -937,7 +938,7 @@ func TestRecordError(t *testing.T) {
 				{
 					Name: errorEventName,
 					Time: errTime,
-					Attributes: []core.KeyValue{
+					Attributes: []kv.KeyValue{
 						errorTypeKey.String(s.typ),
 						errorMessageKey.String(s.msg),
 					},
@@ -983,7 +984,7 @@ func TestRecordErrorWithStatus(t *testing.T) {
 			{
 				Name: errorEventName,
 				Time: errTime,
-				Attributes: []core.KeyValue{
+				Attributes: []kv.KeyValue{
 					errorTypeKey.String("go.opentelemetry.io/otel/internal/testing.TestError"),
 					errorMessageKey.String("test error"),
 				},
@@ -1066,9 +1067,9 @@ func TestWithResource(t *testing.T) {
 	var te testExporter
 	tp, _ := NewProvider(WithSyncer(&te),
 		WithConfig(Config{DefaultSampler: AlwaysSample()}),
-		WithResourceAttributes(key.String("rk1", "rv1"), key.Int64("rk2", 5)))
+		WithResourceAttributes(kv.String("rk1", "rv1"), kv.Int64("rk2", 5)))
 	span := startSpan(tp, "WithResource")
-	span.SetAttributes(key.String("key1", "value1"))
+	span.SetAttributes(kv.String("key1", "value1"))
 	got, err := endSpan(&te, span)
 	if err != nil {
 		t.Error(err.Error())
@@ -1081,12 +1082,12 @@ func TestWithResource(t *testing.T) {
 		},
 		ParentSpanID: sid,
 		Name:         "span0",
-		Attributes: []core.KeyValue{
-			key.String("key1", "value1"),
+		Attributes: []kv.KeyValue{
+			kv.String("key1", "value1"),
 		},
 		SpanKind:        apitrace.SpanKindInternal,
 		HasRemoteParent: true,
-		Resource:        resource.New(key.String("rk1", "rv1"), key.Int64("rk2", 5)),
+		Resource:        resource.New(kv.String("rk1", "rv1"), kv.Int64("rk2", 5)),
 	}
 	if diff := cmpDiff(got, want); diff != "" {
 		t.Errorf("WithResource:\n  -got +want %s", diff)