diff --git a/readme.md b/readme.md
index 8ae00f545f..60df6faf73 100644
--- a/readme.md
+++ b/readme.md
@@ -130,7 +130,8 @@ Each of the generator properties (like `name`, `address`, and `lorem`) are calle
 
 ### `Faker\Provider\en_US\PhoneNumber`
 
-    phoneNumber             // '132-149-0269x3767'
+    phoneNumber             // '201-886-0269 x3767'
+    tollFreePhoneNumber     // '(888) 937-7238'
 
 ### `Faker\Provider\en_US\Company`
 
diff --git a/src/Faker/Provider/Base.php b/src/Faker/Provider/Base.php
index 9cfda63a47..4ca7f045fc 100644
--- a/src/Faker/Provider/Base.php
+++ b/src/Faker/Provider/Base.php
@@ -46,6 +46,21 @@ public static function randomDigitNotNull()
         return mt_rand(1, 9);
     }
 
+    /**
+     * Generates a random digit, which cannot be $except
+     *
+     * @param int $except
+     * @return int
+     */
+    public static function randomDigitNot($except)
+    {
+        $result = self::numberBetween(0, 8);
+        if ($result >= $except) {
+            $result++;
+        }
+        return $result;
+    }
+
     /**
      * Returns a random integer with 0 to $nbDigits digits.
      *
diff --git a/src/Faker/Provider/PhoneNumber.php b/src/Faker/Provider/PhoneNumber.php
index 65b24fc2ae..a010d43e96 100644
--- a/src/Faker/Provider/PhoneNumber.php
+++ b/src/Faker/Provider/PhoneNumber.php
@@ -9,8 +9,8 @@ class PhoneNumber extends \Faker\Provider\Base
     /**
      * @example '555-123-546'
      */
-    public static function phoneNumber()
+    public function phoneNumber()
     {
-        return static::numerify(static::randomElement(static::$formats));
+        return static::numerify($this->generator->parse(static::randomElement(static::$formats)));
     }
 }
diff --git a/src/Faker/Provider/bn_BD/PhoneNumber.php b/src/Faker/Provider/bn_BD/PhoneNumber.php
index 9410ef1285..b6dcc62b94 100644
--- a/src/Faker/Provider/bn_BD/PhoneNumber.php
+++ b/src/Faker/Provider/bn_BD/PhoneNumber.php
@@ -4,7 +4,7 @@
 
 class PhoneNumber extends \Faker\Provider\PhoneNumber
 {
-    public static function phoneNumber()
+    public function phoneNumber()
     {
         $number = "+880";
         $number .= static::randomNumber(7);
diff --git a/src/Faker/Provider/en_AU/PhoneNumber.php b/src/Faker/Provider/en_AU/PhoneNumber.php
index abf697c2d2..238c9ce92b 100644
--- a/src/Faker/Provider/en_AU/PhoneNumber.php
+++ b/src/Faker/Provider/en_AU/PhoneNumber.php
@@ -44,13 +44,6 @@ class PhoneNumber extends \Faker\Provider\PhoneNumber
         '2', '3', '7', '8'
     );
 
-    public static function phoneNumber()
-    {
-        $format = static::numerify(static::randomElement(static::$formats));
-
-        return str_replace('{{areaCode}}', static::areaCode(), $format);
-    }
-
     public static function mobileNumber()
     {
         return static::numerify(static::randomElement(static::$mobileFormats));
diff --git a/src/Faker/Provider/en_NZ/PhoneNumber.php b/src/Faker/Provider/en_NZ/PhoneNumber.php
index b06a10235b..8695c9f330 100644
--- a/src/Faker/Provider/en_NZ/PhoneNumber.php
+++ b/src/Faker/Provider/en_NZ/PhoneNumber.php
@@ -10,8 +10,8 @@ class PhoneNumber extends \Faker\Provider\PhoneNumber
      */
     protected static $formats = array(
         // National Calls
-        '{{area_code}}{{beginning_number}}######',
-        '{{area_code}} {{beginning_number}}## ####'
+        '{{areaCode}}{{beginningNumber}}######',
+        '{{areaCode}} {{beginningNumber}}## ####'
     );
 
     /**
@@ -55,19 +55,6 @@ class PhoneNumber extends \Faker\Provider\PhoneNumber
         '2', '3', '4', '5', '6', '7', '8', '9'
     );
 
-    /**
-     * Return a en_NZ landline phone number
-     * @return string
-     */
-    public static function phoneNumber()
-    {
-        $format = static::numerify(static::randomElement(static::$formats));
-
-        $withAreaCode = str_replace('{{area_code}}', static::areaCode(), $format);
-
-        return str_replace('{{beginning_number}}', static::beginningNumber(), $withAreaCode);
-    }
-
     /**
      * Return a en_NZ mobile phone number
      * @return string
diff --git a/src/Faker/Provider/en_US/PhoneNumber.php b/src/Faker/Provider/en_US/PhoneNumber.php
index 2a698317e2..dc5d59833c 100644
--- a/src/Faker/Provider/en_US/PhoneNumber.php
+++ b/src/Faker/Provider/en_US/PhoneNumber.php
@@ -4,30 +4,105 @@
 
 class PhoneNumber extends \Faker\Provider\PhoneNumber
 {
+    /**
+     * @see https://en.wikipedia.org/wiki/National_conventions_for_writing_telephone_numbers#United_States.2C_Canada.2C_and_other_NANP_countries
+     */
     protected static $formats = array(
-        '+##(#)##########',
-        '+##(#)##########',
-        '0##########',
-        '0##########',
-        '###-###-####',
-        '(###)###-####',
-        '1-###-###-####',
-        '###.###.####',
-        '###-###-####',
-        '(###)###-####',
-        '1-###-###-####',
-        '###.###.####',
-        '###-###-####x###',
-        '(###)###-####x###',
-        '1-###-###-####x###',
-        '###.###.####x###',
-        '###-###-####x####',
-        '(###)###-####x####',
-        '1-###-###-####x####',
-        '###.###.####x####',
-        '###-###-####x#####',
-        '(###)###-####x#####',
-        '1-###-###-####x#####',
-        '###.###.####x#####'
+        // International format
+        '+1-{{areaCode}}-{{exchangeCode}}-####',
+        '+1 ({{areaCode}}) {{exchangeCode}}-####',
+        '+1-{{areaCode}}-{{exchangeCode}}-####',
+        '+1.{{areaCode}}.{{exchangeCode}}.####',
+        '+1{{areaCode}}{{exchangeCode}}####',
+
+        // Standard formats
+        '{{areaCode}}-{{exchangeCode}}-####',
+        '({{areaCode}}) {{exchangeCode}}-####',
+        '1-{{areaCode}}-{{exchangeCode}}-####',
+        '{{areaCode}}.{{exchangeCode}}.####',
+
+        '{{areaCode}}-{{exchangeCode}}-####',
+        '({{areaCode}}) {{exchangeCode}}-####',
+        '1-{{areaCode}}-{{exchangeCode}}-####',
+        '{{areaCode}}.{{exchangeCode}}.####',
+
+        // Extensions
+        '{{areaCode}}-{{exchangeCode}}-#### x###',
+        '({{areaCode}}) {{exchangeCode}}-#### x###',
+        '1-{{areaCode}}-{{exchangeCode}}-#### x###',
+        '{{areaCode}}.{{exchangeCode}}.#### x###',
+
+        '{{areaCode}}-{{exchangeCode}}-#### x####',
+        '({{areaCode}}) {{exchangeCode}}-#### x####',
+        '1-{{areaCode}}-{{exchangeCode}}-#### x####',
+        '{{areaCode}}.{{exchangeCode}}.#### x####',
+
+        '{{areaCode}}-{{exchangeCode}}-#### x#####',
+        '({{areaCode}}) {{exchangeCode}}-#### x#####',
+        '1-{{areaCode}}-{{exchangeCode}}-#### x#####',
+        '{{areaCode}}.{{exchangeCode}}.#### x#####'
+    );
+
+    /**
+     * @see https://en.wikipedia.org/wiki/Toll-free_telephone_number#United_States
+     */
+    protected static $tollFreeAreaCodes = array(
+        800, 844, 855, 866, 877, 888
+    );
+    protected static $tollFreeFormats = array(
+        // Standard formats
+        '{{tollFreeAreaCode}}-{{exchangeCode}}-####',
+        '({{tollFreeAreaCode}}) {{exchangeCode}}-####',
+        '1-{{tollFreeAreaCode}}-{{exchangeCode}}-####',
+        '{{tollFreeAreaCode}}.{{exchangeCode}}.####',
     );
+
+    public function tollFreeAreaCode()
+    {
+        return self::randomElement(static::$tollFreeAreaCodes);
+    }
+
+    public function tollFreePhoneNumber()
+    {
+        $format = self::randomElement(static::$tollFreeFormats);
+
+        return self::numerify($this->generator->parse($format));
+    }
+
+    /**
+     * NPA-format area code
+     *
+     * @see https://en.wikipedia.org/wiki/North_American_Numbering_Plan#Numbering_system
+     *
+     * @return string
+     */
+    public static function areaCode()
+    {
+        $digits[] = self::numberBetween(2, 9);
+        $digits[] = self::randomDigit();
+        $digits[] = self::randomDigitNot($digits[1]);
+
+        return join('', $digits);
+    }
+
+    /**
+     * NXX-format central office exchange code
+     *
+     * @see https://en.wikipedia.org/wiki/North_American_Numbering_Plan#Numbering_system
+     *
+     * @return string
+     */
+    public static function exchangeCode()
+    {
+        $digits[] = self::numberBetween(2, 9);
+        $digits[] = self::randomDigit();
+
+        if ($digits[1] === 1) {
+            $digits[] = self::randomDigitNot(1);
+        } else {
+            $digits[] = self::randomDigit();
+        }
+
+        return join('', $digits);
+    }
 }
diff --git a/src/Faker/Provider/pt_BR/PhoneNumber.php b/src/Faker/Provider/pt_BR/PhoneNumber.php
index c66b0096a6..bfca3378e7 100644
--- a/src/Faker/Provider/pt_BR/PhoneNumber.php
+++ b/src/Faker/Provider/pt_BR/PhoneNumber.php
@@ -124,7 +124,7 @@ public static function landlineNumber($formatted = true)
      * Randomizes between complete cellphone and landline numbers.
      * @return mixed
      */
-    public static function phoneNumber()
+    public function phoneNumber()
     {
         $method = static::randomElement(array('cellphoneNumber', 'landlineNumber'));
         return call_user_func("static::$method", true);
diff --git a/src/Faker/Provider/ro_RO/PhoneNumber.php b/src/Faker/Provider/ro_RO/PhoneNumber.php
index 9e3c07fed4..e8af8101ce 100644
--- a/src/Faker/Provider/ro_RO/PhoneNumber.php
+++ b/src/Faker/Provider/ro_RO/PhoneNumber.php
@@ -43,7 +43,7 @@ class PhoneNumber extends \Faker\Provider\PhoneNumber
     /**
      * @link http://en.wikipedia.org/wiki/Telephone_numbers_in_Romania#Last_years
      */
-    public static function phoneNumber()
+    public function phoneNumber()
     {
         $type = static::randomElement(array_keys(static::$normalFormats));
         $number = static::numerify(static::randomElement(static::$normalFormats[$type]));
diff --git a/src/Faker/Provider/vi_VN/PhoneNumber.php b/src/Faker/Provider/vi_VN/PhoneNumber.php
index 694e3951e6..5f9f60a1e7 100644
--- a/src/Faker/Provider/vi_VN/PhoneNumber.php
+++ b/src/Faker/Provider/vi_VN/PhoneNumber.php
@@ -46,7 +46,7 @@ class PhoneNumber extends \Faker\Provider\PhoneNumber
         ),
     );
 
-    public static function phoneNumber()
+    public function phoneNumber()
     {
         $areaCode = static::randomElement(static::$areaCodes);
         $areaCodeLength = strlen($areaCode);
diff --git a/src/Faker/Provider/zh_CN/PhoneNumber.php b/src/Faker/Provider/zh_CN/PhoneNumber.php
index 2811aa122f..dc4dcab89a 100644
--- a/src/Faker/Provider/zh_CN/PhoneNumber.php
+++ b/src/Faker/Provider/zh_CN/PhoneNumber.php
@@ -12,7 +12,7 @@ class PhoneNumber extends \Faker\Provider\PhoneNumber
 
     protected static $formats = array('########');
 
-    public static function phoneNumber()
+    public function phoneNumber()
     {
         $operators = static::randomElement(static::$operators);
 
diff --git a/test/Faker/Provider/BaseTest.php b/test/Faker/Provider/BaseTest.php
index 95e694ab6e..a426dc62d7 100644
--- a/test/Faker/Provider/BaseTest.php
+++ b/test/Faker/Provider/BaseTest.php
@@ -23,6 +23,16 @@ public function testRandomDigitNotNullReturnsNotNullDigit()
         $this->assertTrue(BaseProvider::randomDigitNotNull() < 10);
     }
 
+
+    public function testRandomDigitNotReturnsValidDigit()
+    {
+        for ($i = 0; $i <= 9; $i++) {
+            $this->assertTrue(BaseProvider::randomDigitNot($i) >= 0);
+            $this->assertTrue(BaseProvider::randomDigitNot($i) < 10);
+            $this->assertTrue(BaseProvider::randomDigitNot($i) !== $i);
+        }
+    }
+
     /**
      * @expectedException \InvalidArgumentException
      */
diff --git a/test/Faker/Provider/en_US/PhoneNumberTest.php b/test/Faker/Provider/en_US/PhoneNumberTest.php
new file mode 100644
index 0000000000..ae2951a57f
--- /dev/null
+++ b/test/Faker/Provider/en_US/PhoneNumberTest.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace Faker\Test\Provider\en_US;
+
+use Faker\Generator;
+use Faker\Provider\en_US\PhoneNumber;
+
+class PhoneNumberTest extends \PHPUnit_Framework_TestCase
+{
+
+    /**
+     * @var Generator
+     */
+    private $faker;
+
+    public function setUp()
+    {
+        $faker = new Generator();
+        $faker->addProvider(new PhoneNumber($faker));
+        $this->faker = $faker;
+    }
+
+    public function testPhoneNumber()
+    {
+        for ($i = 0; $i < 100; $i++) {
+            $number = $this->faker->phoneNumber;
+            $baseNumber = preg_replace('/ *x.*$/', '', $number); // Remove possible extension
+            $digits = array_values(array_filter(str_split($baseNumber), 'ctype_digit'));
+
+            // Prefix '1' allowed
+            if (count($digits) === 11) {
+                $this->assertEquals('1', $digits[0]);
+                $digits = array_slice($digits, 1);
+            }
+
+            // 10 digits
+            $this->assertEquals(10, count($digits));
+
+            // Last two digits of area code cannot be identical
+            $this->assertNotEquals($digits[1], $digits[2]);
+
+            // Last two digits of exchange code cannot be 1
+            if ($digits[4] === 1) {
+                $this->assertNotEquals($digits[4], $digits[5]);
+            }
+
+            // Test format
+            $this->assertRegExp('/^(\+?1)?([ -.]*\d{3}[ -.]*| *\(\d{3}\) *)\d{3}[-.]?\d{4}$/', $baseNumber);
+        }
+    }
+
+    public function testTollFreeAreaCode()
+    {
+        $this->assertContains($this->faker->tollFreeAreaCode, array(800, 822, 833, 844, 855, 866, 877, 888, 880, 887, 889));
+    }
+
+    public function testTollFreePhoneNumber()
+    {
+        for ($i = 0; $i < 100; $i++) {
+            $number = $this->faker->tollFreePhoneNumber;
+            $digits = array_values(array_filter(str_split($number), 'ctype_digit'));
+
+            // Prefix '1' allowed
+            if (count($digits) === 11) {
+                $this->assertEquals('1', $digits[0]);
+                $digits = array_slice($digits, 1);
+            }
+
+            // 10 digits
+            $this->assertEquals(10, count($digits));
+
+            $areaCode = $digits[0] . $digits[1] . $digits[2];
+            $this->assertContains($areaCode, array('800', '822', '833', '844', '855', '866', '877', '888', '880', '887', '889'));
+
+            // Last two digits of exchange code cannot be 1
+            if ($digits[4] === 1) {
+                $this->assertNotEquals($digits[4], $digits[5]);
+            }
+
+            // Test format
+            $this->assertRegExp('/^(\+?1)?([ -.]*\d{3}[ -.]*| *\(\d{3}\) *)\d{3}[-.]?\d{4}$/', $number);
+        }
+    }
+}