Here is simple example. A contact has one to many associated phone numbers. When a contact is deleted, I want all its associated phone numbers
to also be deleted, so I use ON DELETE CASCADE. The one-to-many/many-to-one relationship is implemented with by the foreign key in the phone_numbers. 
CREATE TABLE contacts
 (contact_id BIGINT AUTO_INCREMENT NOT NULL,
 name VARCHAR(75) NOT NULL,
 PRIMARY KEY(contact_id)) ENGINE = InnoDB;
CREATE TABLE phone_numbers
 (phone_id BIGINT AUTO_INCREMENT NOT NULL,
  phone_number CHAR(10) NOT NULL,
 contact_id BIGINT NOT NULL,
 PRIMARY KEY(phone_id),
 UNIQUE(phone_number)) ENGINE = InnoDB;
ALTER TABLE phone_numbers ADD FOREIGN KEY (contact_id) REFERENCES \
contacts(contact_id) ) ON DELETE CASCADE;
By adding "ON DELETE CASCADE" to the foreign key constraint, phone_numbers will automatically be deleted when their associated contact is
deleted.
INSERT INTO table contacts(name) VALUES('Robert Smith');
INSERT INTO table phone_numbers(phone_number, contact_id) VALUES('8963333333', 1);
INSERT INTO table phone_numbers(phone_number, contact_id) VALUES('8964444444', 1);
Now when a row in the contacts table is deleted, all its associated phone_numbers rows will automatically be deleted.
DELETE TABLE contacts as c WHERE c.id=1; /* delete cascades to phone_numbers */
To achieve the same thing in Doctrine, to get the same DB-level "ON DELETE CASCADE" behavoir, you configure the @JoinColumn with
the onDelete="CASCADE" option. 
<?php
namespace Entities;
use Doctrine\Common\Collections\ArrayCollection;
/**
 * @Entity
 * @Table(name="contacts")
 */
class Contact 
{
    /**
     *  @Id
     *  @Column(type="integer", name="contact_id") 
     *  @GeneratedValue
     */
    protected $id;  
    /** 
     * @Column(type="string", length="75", unique="true") 
     */ 
    protected $name; 
    /** 
     * @OneToMany(targetEntity="Phonenumber", mappedBy="contact")
     */ 
    protected $phonenumbers; 
    public function __construct($name=null)
    {
        $this->phonenumbers = new ArrayCollection();
        if (!is_null($name)) {
            $this->name = $name;
        }
    }
    public function getId()
    {
        return $this->id;
    }
    public function setName($name)
    {
        $this->name = $name;
    }
    public function addPhonenumber(Phonenumber $p)
    {
        if (!$this->phonenumbers->contains($p)) {
            $this->phonenumbers[] = $p;
            $p->setContact($this);
        }
    }
    public function removePhonenumber(Phonenumber $p)
    {
        $this->phonenumbers->remove($p);
    }
}
<?php
namespace Entities;
/**
 * @Entity
 * @Table(name="phonenumbers")
 */
class Phonenumber 
{
    /**
    * @Id
    * @Column(type="integer", name="phone_id") 
    * @GeneratedValue
    */
    protected $id; 
    /**
     * @Column(type="string", length="10", unique="true") 
     */  
    protected $number;
    /** 
     * @ManyToOne(targetEntity="Contact", inversedBy="phonenumbers")
     * @JoinColumn(name="contact_id", referencedColumnName="contact_id", onDelete="CASCADE")
     */ 
    protected $contact; 
    public function __construct($number=null)
    {
        if (!is_null($number)) {
            $this->number = $number;
        }
    }
    public function setPhonenumber($number)
    {
        $this->number = $number;
    }
    public function setContact(Contact $c)
    {
        $this->contact = $c;
    }
} 
?>
<?php
$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);
$contact = new Contact("John Doe"); 
$phone1 = new Phonenumber("8173333333");
$phone2 = new Phonenumber("8174444444");
$em->persist($phone1);
$em->persist($phone2);
$contact->addPhonenumber($phone1); 
$contact->addPhonenumber($phone2); 
$em->persist($contact);
try {
    $em->flush();
} catch(Exception $e) {
    $m = $e->getMessage();
    echo $m . "<br />\n";
}
If you now do 
# doctrine orm:schema-tool:create --dump-sql
you will see that the same SQL will be generated as in the first, raw-SQL example